home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / Main.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-28  |  81.7 KB  |  2,898 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "VirtualDub.h"
  19.  
  20. #include <stdio.h>
  21. #include <process.h>
  22. #include <crtdbg.h>
  23.  
  24. #include <windows.h>
  25. #include <commctrl.h>
  26. #include <commdlg.h>
  27. #include <mmsystem.h>
  28. #include <vfw.h>
  29. #include <shellapi.h>
  30. #include <shlobj.h>
  31.  
  32. #include "resource.h"
  33. #include "convert.h"
  34. #include "optdlg.h"
  35. #include "prefs.h"
  36. #include "filtdlg.h"
  37. #include "filters.h"
  38. #include "audio.h"
  39. #include "oshelper.h"
  40. #include "gui.h"
  41. #include "ClippingControl.h"
  42. #include "PositionControl.h"
  43. #include "HexViewer.h"
  44. #include "cpuaccel.h"
  45. #include "capture.h"
  46. #include "auxdlg.h"
  47. #include "dub.h"
  48. #include "DubStatus.h"
  49. #include "mpeg.h"
  50. #include "ddrawsup.h"
  51. #include "server.h"
  52. #include "script.h"
  53. #include "command.h"
  54. #include "job.h"
  55. #include "autodetect.h"
  56. #include "crash.h"
  57.  
  58. #include "AudioSource.h"
  59. #include "VideoSource.h"
  60. #include "AVIStripeSystem.h"
  61. #include "AVIOutput.h"
  62. #include "AVIOutputStriped.h"
  63. #include "AVIOutputPreview.h"
  64. #include "AVIOutputImages.h"
  65. #include "AVIPipe.h"
  66. #include "AsyncBlitter.h"
  67. #include "InputFile.h"
  68. #include "MRUList.h"
  69. #include "SceneDetector.h"
  70. #include "Error.h"
  71. #include "FrameSubset.h"
  72.  
  73. ///////////////////////////////////////////////////////////////////////////
  74.  
  75. #define MRU_LIST_POSITION        (22)
  76.  
  77. ///////////////////////////////////////////////////////////////////////////
  78.  
  79. extern bool g_fJobMode;
  80. extern bool g_fJobAborted;
  81.  
  82. HINSTANCE    g_hInst;
  83. HWND        g_hWnd =NULL;
  84. HMENU        hMenuNormal, hMenuDub, g_hmenuDisplay;
  85. HACCEL        g_hAccelMain;
  86.  
  87. HDC                    hDCWindow                = NULL;
  88. HDRAWDIB            hDDWindow                = NULL;
  89. HDRAWDIB            hDDWindow2                = NULL;
  90.  
  91. MRUList                *mru_list                = NULL;
  92.  
  93. SceneDetector        *g_sceneDetector        = NULL;
  94.  
  95. int                    g_sceneShuttleMode        = 0;
  96. int                    g_sceneShuttleAdvance    = 0;
  97. int                    g_sceneShuttleCounter    = 0;
  98.  
  99. bool                g_fDropFrames            = false;
  100. bool                g_fSwapPanes            = false;
  101.  
  102. IDubStatusHandler    *g_dubStatus            = NULL;
  103.  
  104. RECT    g_rInputFrame;
  105. RECT    g_rOutputFrame;
  106. int        g_iInputFrameShift = 0;
  107. int        g_iOutputFrameShift = 0;
  108.  
  109. char g_szInputAVIFile[MAX_PATH];
  110. char g_szInputAVIFileTitle[MAX_PATH];
  111. char g_szInputWAVFile[MAX_PATH];
  112. char g_szFile[MAX_PATH];
  113. char g_msgBuf[128];
  114. char g_szFileDescription[256];
  115.  
  116. extern const char g_szError[]="VirtualDub Error";
  117. extern const char g_szWarning[]="VirtualDub Warning";
  118. extern const char g_szOutOfMemory[]="Out of memory";
  119. static char szWAVOutput[]="WAVOutput";
  120.  
  121. ///////////////////////////
  122.  
  123. extern bool Init(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow);
  124. extern void Deinit();
  125. extern bool CoachCheckSaveOp(HWND hwndParent, DubOptions *dopt, COMPVARS *vcomp, WAVEFORMATEX *, List *);
  126. extern void ChooseCompressor(HWND hwndParent, COMPVARS *lpCompVars, BITMAPINFOHEADER *bihInput);
  127. extern void FreeCompressor(COMPVARS *pCompVars);
  128. extern WAVEFORMATEX *AudioChooseCompressor(HWND hwndParent, WAVEFORMATEX *, WAVEFORMATEX *);
  129. extern void DisplayLicense(HWND hwndParent);
  130.  
  131. LONG APIENTRY MainWndProc( HWND hWnd, UINT message, UINT wParam, LONG lParam);
  132. void SceneShuttleStop();
  133. void SceneShuttleStep();
  134.  
  135. void SetTitleByFile(HWND hWnd);
  136. void RecalcFrameSizes();
  137.  
  138. void SetAudioSource();
  139. void OpenAVI(int index, bool extended_opt);
  140. void AppendAVI();
  141. void PreviewAVI(HWND, DubOptions *, int iPriority=0, bool fProp=false);
  142. void SaveAVI(HWND, bool);
  143. void SaveSegmentedAVI(HWND);
  144. void HandleDragDrop(HDROP hdrop);
  145. void SaveStripedAVI(HWND);
  146. void SaveStripeMaster(HWND);
  147. void CPUTest();
  148. void InitDubAVI(char *szFile, BOOL fAudioOnly, DubOptions *quick_options, int iPriority=0, bool fPropagateErrors = false, long lSpillThreshold=0, long lSpillFrameThreshold=0);
  149. void SaveImageSeq(HWND);
  150. void SaveWAV(HWND);
  151. void OpenWAV();
  152. void DoDelete();
  153. void SaveConfiguration(HWND);
  154.  
  155. BOOL APIENTRY StatusDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam);
  156. BOOL APIENTRY AVIInfoDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam);
  157.  
  158. //
  159. //  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  160. //
  161. //  PURPOSE: Entry point for the application.
  162. //
  163. //  COMMENTS:
  164. //
  165. //    This function initializes the application and processes the
  166. //    message loop.
  167. //
  168.  
  169. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  170.     LPSTR lpCmdLine, int nCmdShow )
  171. {
  172.     MSG msg;
  173.  
  174.     Init(hInstance, lpCmdLine, nCmdShow);
  175.  
  176.     // Load a file on the command line.
  177.  
  178.     VDCHECKPOINT;
  179.  
  180.     if (*g_szFile)
  181.         try {
  182.             char szFileTmp[MAX_PATH];
  183.             char *t;
  184.  
  185.             strcpy(g_szInputAVIFile, g_szFile);
  186.             GetFullPathName(g_szInputAVIFile, sizeof szFileTmp, szFileTmp, &t);
  187.             strcpy(g_szInputAVIFileTitle, t);
  188.  
  189.             OpenAVI(g_szFile, 0, false, false, NULL);
  190.             SetTitleByFile(g_hWnd);
  191.             RecalcFrameSizes();
  192.             InvalidateRect(g_hWnd, NULL, TRUE);
  193.  
  194.         } catch(MyError e) {
  195.             e.post(g_hWnd, g_szError);
  196.         }
  197.  
  198.     // Acquire and dispatch messages until a WM_QUIT message is received.
  199.     VDCHECKPOINT;
  200.  
  201.     while (GetMessage(&msg,NULL,0,0)) {
  202.  
  203.         if (guiCheckDialogs(&msg)) continue;
  204.  
  205.         if (!g_dubber) {
  206.             HWND hwnd = msg.hwnd, hwndParent;
  207.  
  208.             while(hwndParent = GetParent(hwnd))
  209.                 hwnd = hwndParent;
  210.  
  211.             if (hwnd == g_hWnd && TranslateAccelerator(g_hWnd, g_hAccelMain, &msg)) continue;
  212.         }
  213.  
  214.         TranslateMessage(&msg);
  215.         DispatchMessage(&msg);
  216.  
  217.         if (!g_dubber && inputVideoAVI && g_sceneShuttleMode) {
  218.             if (!g_sceneDetector)
  219.                 if (!(g_sceneDetector = new SceneDetector(inputVideoAVI->getImageFormat()->biWidth, inputVideoAVI->getImageFormat()->biHeight)))
  220.                     continue;
  221.  
  222.             g_sceneDetector->SetThresholds(g_prefs.scene.iCutThreshold, g_prefs.scene.iFadeThreshold);
  223.  
  224.             while(g_sceneShuttleMode) {
  225.                 SceneShuttleStep();
  226.  
  227.                 while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  228.                     if (msg.message == WM_QUIT) goto wm_quit_detected;
  229.  
  230.                     guiCheckDialogs(&msg);
  231.  
  232.                     if (TranslateAccelerator(g_hWnd, g_hAccelMain, &msg)) continue;
  233.  
  234.                     TranslateMessage(&msg);
  235.                     DispatchMessage(&msg);
  236.                 }
  237.             }
  238.  
  239.             delete g_sceneDetector;
  240.             g_sceneDetector = NULL;
  241.         }
  242.     }
  243. wm_quit_detected:
  244.  
  245.     Deinit();
  246.  
  247.     VDCHECKPOINT;
  248.  
  249.     return (msg.wParam);           // Returns the value from PostQuitMessage.
  250.  
  251. }
  252.  
  253.  
  254. //////////////////////////////////////////////////////////////////////
  255.  
  256. #define MENU_TO_HELP(x) ID_##x, IDS_##x
  257.  
  258. UINT iMainMenuHelpTranslator[]={
  259.     MENU_TO_HELP(FILE_OPENAVI),
  260.     MENU_TO_HELP(FILE_PREVIEWAVI),
  261.     MENU_TO_HELP(FILE_SAVEAVI),
  262.     MENU_TO_HELP(FILE_SAVECOMPATIBLEAVI),
  263.     MENU_TO_HELP(FILE_SAVESTRIPEDAVI),
  264.     MENU_TO_HELP(FILE_SAVEIMAGESEQ),
  265.     MENU_TO_HELP(FILE_CLOSEAVI),
  266.     MENU_TO_HELP(FILE_CAPTUREAVI),
  267.     MENU_TO_HELP(FILE_STARTSERVER),
  268.     MENU_TO_HELP(FILE_AVIINFO),
  269.     MENU_TO_HELP(FILE_SAVEWAV),
  270.     MENU_TO_HELP(FILE_QUIT),
  271.     MENU_TO_HELP(FILE_LOADCONFIGURATION),
  272.     MENU_TO_HELP(FILE_SAVECONFIGURATION),
  273.  
  274.     MENU_TO_HELP(VIDEO_SEEK_START),
  275.     MENU_TO_HELP(VIDEO_SEEK_END),
  276.     MENU_TO_HELP(VIDEO_SEEK_PREV),
  277.     MENU_TO_HELP(VIDEO_SEEK_NEXT),
  278.     MENU_TO_HELP(VIDEO_SEEK_KEYPREV),
  279.     MENU_TO_HELP(VIDEO_SEEK_KEYNEXT),
  280.     MENU_TO_HELP(VIDEO_SEEK_SELSTART),
  281.     MENU_TO_HELP(VIDEO_SEEK_SELEND),
  282.     MENU_TO_HELP(VIDEO_SEEK_PREVDROP),
  283.     MENU_TO_HELP(VIDEO_SEEK_NEXTDROP),
  284.     MENU_TO_HELP(EDIT_JUMPTO),
  285.     MENU_TO_HELP(EDIT_DELETE),
  286.     MENU_TO_HELP(EDIT_SETSELSTART),
  287.     MENU_TO_HELP(EDIT_SETSELEND),
  288.  
  289.     MENU_TO_HELP(VIDEO_FILTERS),
  290.     MENU_TO_HELP(VIDEO_FRAMERATE),
  291.     MENU_TO_HELP(VIDEO_COLORDEPTH),
  292.     MENU_TO_HELP(VIDEO_COMPRESSION),
  293.     MENU_TO_HELP(VIDEO_CLIPPING),
  294.     MENU_TO_HELP(VIDEO_MODE_DIRECT),
  295.     MENU_TO_HELP(VIDEO_MODE_FASTRECOMPRESS),
  296.     MENU_TO_HELP(VIDEO_MODE_NORMALRECOMPRESS),
  297.     MENU_TO_HELP(VIDEO_MODE_FULL),
  298.     MENU_TO_HELP(AUDIO_CONVERSION),
  299.     MENU_TO_HELP(AUDIO_INTERLEAVE),
  300.     MENU_TO_HELP(AUDIO_COMPRESSION),
  301.     MENU_TO_HELP(AUDIO_SOURCE_NONE),
  302.     MENU_TO_HELP(AUDIO_SOURCE_AVI),
  303.     MENU_TO_HELP(AUDIO_SOURCE_WAV),
  304.     MENU_TO_HELP(AUDIO_MODE_DIRECT),
  305.     MENU_TO_HELP(AUDIO_MODE_FULL),
  306.     MENU_TO_HELP(OPTIONS_PREFERENCES),
  307.     MENU_TO_HELP(OPTIONS_PERFORMANCE),
  308.     MENU_TO_HELP(OPTIONS_DYNAMICCOMPILATION),
  309.     MENU_TO_HELP(OPTIONS_DISPLAYINPUTVIDEO),
  310.     MENU_TO_HELP(OPTIONS_DISPLAYOUTPUTVIDEO),
  311.     MENU_TO_HELP(OPTIONS_DISPLAYDECOMPRESSEDOUTPUT),
  312.     MENU_TO_HELP(OPTIONS_ENABLEMMX),
  313.     MENU_TO_HELP(OPTIONS_SHOWSTATUSWINDOW),
  314.     MENU_TO_HELP(OPTIONS_SYNCHRONOUSBLIT),
  315.     MENU_TO_HELP(OPTIONS_VERTICALDISPLAY),
  316.     MENU_TO_HELP(OPTIONS_DRAWHISTOGRAMS),
  317.     MENU_TO_HELP(OPTIONS_SYNCTOAUDIO),
  318.     MENU_TO_HELP(OPTIONS_DROPFRAMES),
  319.     MENU_TO_HELP(OPTIONS_ENABLEDIRECTDRAW),
  320.  
  321.     MENU_TO_HELP(HELP_CONTENTS),
  322.     MENU_TO_HELP(HELP_CHANGELOG),
  323.     MENU_TO_HELP(HELP_RELEASENOTES),
  324.     MENU_TO_HELP(HELP_ABOUT),
  325.     NULL,NULL,
  326. };
  327.  
  328. //////////////////////////////////////////////////////////////////////
  329.  
  330. char PositionFrameTypeCallback(HWND hwnd, void *pvData, long pos) {
  331.     try {
  332.         if (inputVideoAVI)
  333.             if (inputSubset)
  334.                 return inputVideoAVI->getFrameTypeChar(inputSubset->lookupFrame(pos));
  335.             else
  336.                 return inputVideoAVI->getFrameTypeChar(pos);
  337.         else
  338.             return 0;
  339.     } catch(MyError e) {
  340.         return 0;
  341.     }
  342. }
  343.  
  344. void DisplayFrame(HWND hWnd, LONG pos, bool bDispInput=true) {
  345.     static FilterStateInfo fsi;
  346.     long original_pos = pos;
  347.  
  348.     if (!g_dubOpts.video.fShowInputFrame && !g_dubOpts.video.fShowOutputFrame)
  349.         return;
  350.  
  351.     try {
  352.         BITMAPINFOHEADER *dcf;
  353.         void *lpBits;
  354.         long limit = inputVideoAVI->lSampleLast;
  355.  
  356.         if (inputSubset) {
  357.             int len = 1;
  358.  
  359.             pos = inputSubset->lookupRange(pos, len);
  360.  
  361.             if (pos < 0)
  362.                 pos = inputVideoAVI->lSampleLast;
  363.         }
  364.  
  365.         dcf = inputVideoAVI->getDecompressedFormat();
  366.  
  367.         if (pos >= inputVideoAVI->lSampleLast) {
  368.             FillRect(hDCWindow, &g_rInputFrame, (HBRUSH)GetClassLong(hWnd,GCL_HBRBACKGROUND));
  369.         } else {
  370.             BITMAPINFOHEADER bihOutput;
  371.             VBitmap *out;
  372.  
  373.             VDCHECKPOINT;
  374.  
  375.             lpBits = inputVideoAVI->getFrame(pos);
  376.  
  377.             VDCHECKPOINT;
  378.  
  379.             if (!lpBits)
  380.                 return;
  381.  
  382.             if (g_dubOpts.video.fShowInputFrame && bDispInput)
  383.                 DrawDibDraw(
  384.                         hDDWindow,
  385.                         hDCWindow,
  386.                         g_rInputFrame.left, g_rInputFrame.top,
  387.                         g_rInputFrame.right-g_rInputFrame.left, g_rInputFrame.bottom-g_rInputFrame.top,
  388.                         dcf,
  389.                         lpBits,
  390.                         0, 0, 
  391.                         dcf->biWidth, dcf->biHeight,
  392.                         0);
  393.  
  394.             VDCHECKPOINT;
  395.  
  396.             if (!g_sceneShuttleMode && !g_dubber && g_dubOpts.video.fShowOutputFrame) {
  397.                 if (!filters.isRunning()) {
  398.                     CPUTest();
  399.                     filters.initLinearChain(&g_listFA, (Pixel *)(dcf+1), dcf->biWidth, dcf->biHeight, 32, 16+8*g_dubOpts.video.outputDepth);
  400.                     if (filters.ReadyFilters(&fsi))
  401.                         throw MyError("can't initialize filters");
  402.                 }
  403.  
  404.                 fsi.lCurrentFrame                = original_pos;
  405.                 fsi.lMicrosecsPerFrame            = MulDiv(inputVideoAVI->streamInfo.dwScale, 1000000, inputVideoAVI->streamInfo.dwRate);
  406.                 fsi.lCurrentSourceFrame            = pos;
  407.                 fsi.lMicrosecsPerSrcFrame        = MulDiv(inputVideoAVI->streamInfo.dwScale, 1000000, inputVideoAVI->streamInfo.dwRate);
  408.                 fsi.lSourceFrameMS                = MulDiv(fsi.lCurrentSourceFrame, fsi.lMicrosecsPerSrcFrame, 1000);
  409.                 fsi.lDestFrameMS                = MulDiv(fsi.lCurrentFrame, fsi.lMicrosecsPerFrame, 1000);
  410.  
  411.                 filters.InputBitmap()->BitBlt(0, 0, &VBitmap(lpBits, dcf), 0, 0, -1, -1);
  412.  
  413.                 filters.RunFilters();
  414.  
  415.                 out = filters.LastBitmap();
  416.  
  417.                 out->MakeBitmapHeader(&bihOutput);
  418.  
  419.                 DrawDibDraw(
  420.                         hDDWindow2,
  421.                         hDCWindow,
  422.                         g_rOutputFrame.left, g_rOutputFrame.top,
  423.                         g_rOutputFrame.right-g_rOutputFrame.left, g_rOutputFrame.bottom-g_rOutputFrame.top,
  424.                         &bihOutput,
  425.                         out->data,
  426.                         0, 0, 
  427.                         out->w, out->h,
  428.                         0);
  429.             }
  430.             VDCHECKPOINT;
  431.         }
  432.  
  433.     } catch(MyError e) {
  434. //        e.post(hWnd, szError);
  435.         guiSetStatus("Error fetching frame %ld: %s", 255, pos, e.gets());
  436.         SceneShuttleStop();
  437.     }
  438. }
  439.  
  440. void SceneShuttleStop() {
  441.     if (g_sceneShuttleMode) {
  442.         HWND hwndPosition = GetDlgItem(g_hWnd, IDC_POSITION);
  443.         LONG lSample = SendMessage(hwndPosition, PCM_GETPOS, 0, 0);
  444.  
  445.         SendMessage(hwndPosition, PCM_RESETSHUTTLE, 0, 0);
  446.         g_sceneShuttleMode = 0;
  447.         g_sceneShuttleAdvance = 0;
  448.         g_sceneShuttleCounter = 0;
  449.         DisplayFrame(g_hWnd, lSample);
  450.     }
  451. }
  452.  
  453. void SceneShuttleStep() {
  454.     HWND hwndPosition = GetDlgItem(g_hWnd, IDC_POSITION);
  455.     LONG lSample = SendMessage(hwndPosition, PCM_GETPOS, 0, 0) + g_sceneShuttleMode;
  456.     long ls2 = inputSubset ? inputSubset->lookupFrame(lSample) : lSample;
  457.  
  458.     if (!inputVideoAVI || ls2 < inputVideoAVI->lSampleFirst || ls2 >= inputVideoAVI->lSampleLast) {
  459.         SceneShuttleStop();
  460.         return;
  461.     }
  462.  
  463.     if (g_sceneShuttleAdvance < 1280)
  464.         ++g_sceneShuttleAdvance;
  465.  
  466.     g_sceneShuttleCounter += 32;
  467.  
  468.     if (g_sceneShuttleCounter >= g_sceneShuttleAdvance) {
  469.         g_sceneShuttleCounter = 0;
  470.         DisplayFrame(g_hWnd, lSample, true);
  471.     } else
  472.         DisplayFrame(g_hWnd, lSample, false);
  473.  
  474.     SendMessage(hwndPosition, PCM_SETPOS, 0, (LPARAM)lSample);
  475.  
  476.     if (g_sceneDetector->Submit(&VBitmap(inputVideoAVI->getFrameBuffer(), inputVideoAVI->getDecompressedFormat()))) {
  477.         SceneShuttleStop();
  478.     }
  479. }
  480.  
  481. void MenuMRUListUpdate(HWND hwnd) {
  482.     HMENU hmenuFile = GetSubMenu(GetMenu(hwnd), 0);
  483.     MENUITEMINFO mii;
  484.     char name[MAX_PATH], name2[MAX_PATH];
  485.     int index=0;
  486.  
  487.     for(;;) {
  488.         memset(&mii, 0, sizeof mii);
  489.         mii.cbSize    = sizeof mii;
  490.         mii.fMask    = MIIM_TYPE;
  491.  
  492.         if (!GetMenuItemInfo(hmenuFile, MRU_LIST_POSITION, TRUE, &mii)) break;
  493.  
  494.         if (mii.fType & MFT_SEPARATOR) break;
  495.  
  496.         RemoveMenu(hmenuFile, MRU_LIST_POSITION, MF_BYPOSITION);
  497.     }
  498.  
  499.     while(!mru_list->get(index, name, sizeof name)) {
  500.         char *s = name;
  501.  
  502.         while(*s) ++s;
  503.         while(s>name && s[-1]!='\\' && s[-1]!=':') --s;
  504.         wsprintf(name2, "&%d %s", (index+1)%10, s);
  505.  
  506.         mii.cbSize        = sizeof mii;
  507.         mii.fMask        = MIIM_TYPE | MIIM_STATE | MIIM_ID;
  508.         mii.fType        = MFT_STRING;
  509.         mii.fState        = MFS_ENABLED;
  510.         mii.wID            = ID_MRU_FILE0 + index;
  511.         mii.dwTypeData    = name2;
  512.  
  513.         if (!InsertMenuItem(hmenuFile, MRU_LIST_POSITION+index, TRUE, &mii))
  514.             break;
  515.         ++index;
  516.     }
  517.  
  518.     if (!index) {
  519.         mii.cbSize        = sizeof mii;
  520.         mii.fMask        = MIIM_TYPE | MIIM_STATE | MIIM_ID;
  521.         mii.fType        = MFT_STRING;
  522.         mii.fState        = MFS_GRAYED;
  523.         mii.wID            = ID_MRU_FILE0;
  524.         mii.dwTypeData    = "Recent file list";
  525.  
  526.         InsertMenuItem(hmenuFile, MRU_LIST_POSITION+index, TRUE, &mii);
  527.     }
  528. }
  529.  
  530. void RecalcFrameSizes() {
  531.     RECT &rInputFrame = g_fSwapPanes ? g_rOutputFrame : g_rInputFrame;
  532.     RECT &rOutputFrame = g_fSwapPanes ? g_rInputFrame : g_rOutputFrame;
  533.  
  534.     memset(&rInputFrame, 0, sizeof(RECT));
  535.     memset(&rOutputFrame, 0, sizeof(RECT));
  536.  
  537.     if (inputVideoAVI) {
  538.         BITMAPINFOHEADER *formatIn = inputVideoAVI->getImageFormat();
  539.  
  540.         if (formatIn) {
  541.             BITMAPINFOHEADER *dcf = inputVideoAVI->getDecompressedFormat();
  542.             int w = dcf->biWidth;
  543.             int h = dcf->biHeight;
  544.             int w2, h2;
  545.  
  546.             if (g_iInputFrameShift<0) {
  547.                 w >>= -g_iInputFrameShift;
  548.                 h >>= -g_iInputFrameShift;
  549.             } else {
  550.                 w <<= g_iInputFrameShift;
  551.                 h <<= g_iInputFrameShift;
  552.             }
  553.  
  554.             g_rInputFrame.left        = 6;
  555.             g_rInputFrame.top        = 6;
  556.             g_rInputFrame.right        = 6 + w;
  557.             g_rInputFrame.bottom    = 6 + h;
  558.  
  559.             // figure out output size too
  560.  
  561.             if (!filters.isRunning()) {
  562.                 if (g_dubber)
  563.                     return;
  564.  
  565.                 filters.prepareLinearChain(&g_listFA, (Pixel *)(dcf+1), dcf->biWidth, dcf->biHeight, 32, 16+8*g_dubOpts.video.outputDepth);
  566.             }
  567.  
  568.             w2 = filters.OutputBitmap()->w;
  569.             h2 = filters.OutputBitmap()->h;
  570.  
  571.             if (g_iOutputFrameShift<0) {
  572.                 w2 >>= -g_iOutputFrameShift;
  573.                 h2 >>= -g_iOutputFrameShift;
  574.             } else {
  575.                 w2 <<= g_iOutputFrameShift;
  576.                 h2 <<= g_iOutputFrameShift;
  577.             }
  578.  
  579.             // If frames are reversed, swap the sizes.
  580.  
  581.             if (g_fSwapPanes) {
  582.                 int t;
  583.  
  584.                 t=w; w=w2; w2=t;
  585.                 t=h; h=h2; h2=t;
  586.             }
  587.  
  588.             // Layout frames.
  589.  
  590.             rInputFrame.left    = 6;
  591.             rInputFrame.top        = 6;
  592.             rInputFrame.right    = 6 + w;
  593.             rInputFrame.bottom    = 6 + h;
  594.  
  595.             if (g_vertical) {
  596.                 rOutputFrame.left    = rInputFrame.left;
  597.                 rOutputFrame.top    = rInputFrame.bottom + 12;
  598.                 rOutputFrame.right    = rOutputFrame.left + w2;
  599.                 rOutputFrame.bottom    = rOutputFrame.top + h2;
  600.             } else {
  601.                 rOutputFrame.left    = rInputFrame.right + 12;
  602.                 rOutputFrame.top    = rInputFrame.top;
  603.                 rOutputFrame.right    = rOutputFrame.left + w2;
  604.                 rOutputFrame.bottom    = rOutputFrame.top + h2;
  605.             }
  606.         }
  607.     }
  608. }
  609.  
  610. void SetTitleByFile(HWND hWnd) {
  611.     if (inputAVI)
  612.         if (g_szFileDescription[0])
  613.             guiSetTitle(hWnd, IDS_TITLE_IDLE2, g_szInputAVIFileTitle, g_szFileDescription);
  614.         else
  615.             guiSetTitle(hWnd, IDS_TITLE_IDLE, g_szInputAVIFileTitle);
  616.     else
  617.         guiSetTitle(hWnd, IDS_TITLE_NOFILE);
  618. }
  619.  
  620. BOOL MenuHit(HWND hWnd, UINT id) {
  621.     if (!g_dubber && id != ID_VIDEO_COPYSOURCEFRAME && id != ID_VIDEO_COPYOUTPUTFRAME) {
  622.         filters.DeinitFilters();
  623.         filters.DeallocateBuffers();
  624.     }
  625.  
  626.     SetAudioSource();
  627.  
  628.     DragAcceptFiles(hWnd, FALSE);
  629.     switch(id) {
  630.     case ID_FILE_QUIT:
  631.         DestroyWindow(hWnd);
  632.         break;
  633.     case ID_FILE_OPENAVI:
  634.         OpenAVI(-1, false);
  635.         RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  636.         break;
  637.     case ID_FILE_APPENDSEGMENT:
  638.         AppendAVI();
  639.         break;
  640.     case ID_FILE_PREVIEWAVI:
  641.         JobLockDubber();
  642.         PreviewAVI(hWnd, NULL, g_prefs.main.iPreviewPriority);
  643.         JobUnlockDubber();
  644.         break;
  645.     case ID_FILE_SAVEAVI:
  646.         JobLockDubber();
  647.         SaveAVI(hWnd, false);
  648.         JobUnlockDubber();
  649.         break;
  650.     case ID_FILE_SAVECOMPATIBLEAVI:
  651.         JobLockDubber();
  652.         SaveAVI(hWnd, true);
  653.         JobUnlockDubber();
  654.         break;
  655.     case ID_FILE_SAVESTRIPEDAVI:
  656.         JobLockDubber();
  657.         SaveStripedAVI(hWnd);
  658.         JobUnlockDubber();
  659.         break;
  660.     case ID_FILE_SAVESTRIPEMASTER:
  661.         JobLockDubber();
  662.         SaveStripeMaster(hWnd);
  663.         JobUnlockDubber();
  664.         break;
  665.     case ID_FILE_SAVEIMAGESEQ:
  666.         JobLockDubber();
  667.         SaveImageSeq(hWnd);
  668.         JobUnlockDubber();
  669.         break;
  670.     case ID_FILE_SAVESEGMENTEDAVI:
  671.         JobLockDubber();
  672.         SaveSegmentedAVI(hWnd);
  673.         JobUnlockDubber();
  674.         break;
  675.     case ID_FILE_SAVEWAV:
  676.         JobLockDubber();
  677.         SaveWAV(hWnd);
  678.         JobUnlockDubber();
  679.         break;
  680.     case ID_FILE_CLOSEAVI:
  681.         CloseAVI();
  682.         RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  683.         break;
  684.     case ID_FILE_STARTSERVER:
  685.         JobLockDubber();
  686.         SetAudioSource();
  687.         ActivateFrameServerDialog(hWnd);
  688.         MenuMRUListUpdate(hWnd);
  689.         JobUnlockDubber();
  690.         break;
  691.     case ID_FILE_CAPTUREAVI:
  692.         JobLockDubber();
  693.         CPUTest();
  694.         Capture(hWnd);
  695.         MenuMRUListUpdate(hWnd);
  696.         JobUnlockDubber();
  697.         break;
  698.     case ID_FILE_SAVECONFIGURATION:
  699.         SaveConfiguration(hWnd);
  700.         break;
  701.     case ID_FILE_LOADCONFIGURATION:
  702.     case ID_FILE_RUNSCRIPT:
  703.         JobLockDubber();
  704.         RunScript(NULL, (void *)hWnd);
  705.         JobUnlockDubber();
  706.         break;
  707.     case ID_FILE_JOBCONTROL:
  708.         OpenJobWindow();
  709.         break;
  710.     case ID_FILE_AVIINFO:
  711. //        if (inputAVI) ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_AVI_INFO), hWnd, AVIInfoDlgProc);
  712.         if (inputAVI)
  713.             inputAVI->InfoDialog(hWnd);
  714.         break;
  715.     case ID_VIDEO_FILTERS:
  716.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_FILTERS), hWnd, FilterDlgProc);
  717.         RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  718.         break;
  719.     case ID_VIDEO_FRAMERATE:
  720.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_VIDEO_FRAMERATE), hWnd, VideoDecimationDlgProc);
  721.         break;
  722.     case ID_VIDEO_COLORDEPTH:
  723.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_VIDEO_DEPTH), hWnd, VideoDepthDlgProc);
  724.         break;
  725.     case ID_VIDEO_CLIPPING:
  726.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_VIDEO_CLIPPING), hWnd, VideoClippingDlgProc);
  727.         break;
  728.     case ID_VIDEO_COMPRESSION:
  729.         if (!(g_Vcompression.dwFlags & ICMF_COMPVARS_VALID)) {
  730.             memset(&g_Vcompression, 0, sizeof g_Vcompression);
  731.             g_Vcompression.dwFlags |= ICMF_COMPVARS_VALID;
  732.             g_Vcompression.lQ = 10000;
  733.         }
  734.  
  735.         g_Vcompression.cbSize = sizeof(COMPVARS);
  736.  
  737. #if 0
  738.         if (inputVideoAVI) {
  739. //            ICCompressorChoose(hWnd, /*ICMF_CHOOSE_DATARATE |*/ ICMF_CHOOSE_KEYFRAME, (void *)inputVideoAVI->getDecompressedFormat(), NULL, &g_Vcompression, "Select video compression");
  740.             ICCompressorChoose(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, NULL, NULL, &g_Vcompression, "Select video compression");
  741.         } else
  742.             ICCompressorChoose(hWnd, ICMF_CHOOSE_ALLCOMPRESSORS | ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, NULL, NULL, &g_Vcompression, "Select video compression");*/
  743. #endif
  744.  
  745.         ChooseCompressor(hWnd, &g_Vcompression, NULL);
  746.  
  747.         break;
  748.     case ID_VIDEO_MODE_DIRECT:
  749.         g_dubOpts.video.mode = DubVideoOptions::M_NONE;
  750.         break;
  751.     case ID_VIDEO_MODE_FASTRECOMPRESS:
  752.         g_dubOpts.video.mode = DubVideoOptions::M_FASTREPACK;
  753.         break;
  754.     case ID_VIDEO_MODE_NORMALRECOMPRESS:
  755.         g_dubOpts.video.mode = DubVideoOptions::M_SLOWREPACK;
  756.         break;
  757.     case ID_VIDEO_MODE_FULL:
  758.         g_dubOpts.video.mode = DubVideoOptions::M_FULL;
  759.         break;
  760.     case ID_VIDEO_COPYSOURCEFRAME:
  761.         if (!inputVideoAVI || !inputVideoAVI->isFrameBufferValid())
  762.             break;
  763.  
  764.         if (OpenClipboard(hWnd)) {
  765.             if (EmptyClipboard()) {
  766.                 BITMAPINFOHEADER *pbih = inputVideoAVI->getDecompressedFormat();
  767.                 long lFormatSize = pbih->biSize + (pbih->biBitCount<=16 ? pbih->biClrUsed*sizeof(RGBQUAD) : 0);
  768.                 HANDLE hMem;
  769.                 void *lpvMem;
  770.  
  771.                 if (hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, pbih->biSizeImage + lFormatSize)) {
  772.                     if (lpvMem = GlobalLock(hMem)) {
  773.                         memcpy(lpvMem, pbih, lFormatSize);
  774.                         memcpy((char *)lpvMem + lFormatSize, inputVideoAVI->getFrameBuffer(), pbih->biSizeImage);
  775.  
  776.                         GlobalUnlock(lpvMem);
  777.                         SetClipboardData(CF_DIB, hMem);
  778.                         CloseClipboard();
  779.                         break;
  780.                     }
  781.                     GlobalFree(hMem);
  782.                 }
  783.             }
  784.             CloseClipboard();
  785.         }
  786.         break;
  787.     case ID_VIDEO_COPYOUTPUTFRAME:
  788.         if (!filters.isRunning())
  789.             break;
  790.         if (OpenClipboard(hWnd)) {
  791.             if (EmptyClipboard()) {
  792.                 BITMAPINFOHEADER bih;
  793.                 long lFormatSize;
  794.                 HANDLE hMem;
  795.                 void *lpvMem;
  796.  
  797.                 filters.LastBitmap()->MakeBitmapHeaderNoPadding(&bih);
  798.                 lFormatSize = bih.biSize;
  799.  
  800.                 if (hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, bih.biSizeImage + lFormatSize)) {
  801.                     if (lpvMem = GlobalLock(hMem)) {
  802.                         memcpy(lpvMem, &bih, lFormatSize);
  803.  
  804.                         VBitmap((char *)lpvMem + lFormatSize, &bih).BitBlt(0, 0, filters.LastBitmap(), 0, 0, -1, -1); 
  805.  
  806.                         GlobalUnlock(lpvMem);
  807.                         SetClipboardData(CF_DIB, hMem);
  808.                         CloseClipboard();
  809.                         break;
  810.                     }
  811.                     GlobalFree(hMem);
  812.                 }
  813.             }
  814.             CloseClipboard();
  815.         }
  816.         break;
  817.  
  818.     case ID_EDIT_DELETE:
  819.         DoDelete();
  820.         break;
  821.  
  822.     case ID_EDIT_SETSELSTART:
  823.         if (inputAVI) {
  824.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETPOS, 0, 0);
  825.  
  826.             SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETSELSTART, (WPARAM)TRUE, lSample);
  827.  
  828.             guiSetStatus("Start offset set to %ld ms", 255,
  829.                     g_dubOpts.video.lStartOffsetMS = inputVideoAVI->samplesToMs(lSample));
  830.         }
  831.         break;
  832.     case ID_EDIT_SETSELEND:
  833.         if (inputAVI) {
  834.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETPOS, 0, 0);
  835.  
  836.             SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETSELEND, (WPARAM)TRUE, lSample);
  837.  
  838.             guiSetStatus("End offset set to %ld ms", 255,
  839.                 g_dubOpts.video.lEndOffsetMS = inputVideoAVI->samplesToMs((inputSubset ? inputSubset->getTotalFrames() : (inputVideoAVI->lSampleLast - inputVideoAVI->lSampleFirst)) - lSample));
  840.         }
  841.         break;
  842.  
  843.     case ID_AUDIO_CONVERSION:
  844.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_AUDIO_CONVERSION), hWnd, AudioConversionDlgProc);
  845.         break;
  846.     case ID_AUDIO_INTERLEAVE:
  847.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_INTERLEAVE), hWnd, AudioInterleaveDlgProc);
  848.         break;
  849.     case ID_AUDIO_COMPRESSION:
  850. #if 0
  851.         {
  852.             ACMFORMATCHOOSE afc;
  853.             DWORD cbFormat;
  854.             WAVEFORMATEX *pFormat;
  855.  
  856.             if (acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &cbFormat))
  857.                 cbFormat = 512;
  858.  
  859.             if (g_ACompressionFormat && g_ACompressionFormatSize > cbFormat)
  860.                 cbFormat = g_ACompressionFormatSize;
  861.  
  862.             if (!(pFormat = (WAVEFORMATEX *)allocmem(cbFormat)))
  863.                 break;
  864.  
  865.             if (g_ACompressionFormat)
  866.                 memcpy(pFormat, g_ACompressionFormat, g_ACompressionFormatSize);
  867.  
  868.             memset(&afc, 0, sizeof afc);
  869.             afc.cbStruct        = sizeof(ACMFORMATCHOOSE);
  870.             afc.fdwStyle        = pFormat ? ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT : 0;
  871.             afc.hwndOwner        = hWnd;
  872.             afc.pwfx            = pFormat;
  873.             afc.cbwfx            = cbFormat;
  874.             afc.pszTitle        = "Select Audio Compression Format";
  875.             afc.szFormatTag[0]    = 0;
  876.             afc.szFormat[0]        = 0;
  877.             afc.pszName            = NULL;
  878.             afc.fdwEnum            = 0;
  879.             afc.pwfxEnum        = NULL;
  880.             afc.hInstance        = NULL;
  881.             afc.pszTemplateName    = NULL;
  882.             afc.pfnHook            = NULL;
  883.  
  884.             if (!acmFormatChoose(&afc)) {
  885.                 freemem(g_ACompressionFormat);
  886.                 g_ACompressionFormat = pFormat;
  887.                 g_ACompressionFormatSize = cbFormat;
  888.             } else
  889.                 freemem(pFormat);
  890.         }
  891. #else
  892.         SetAudioSource();
  893.  
  894.         if (!inputAudio)
  895.             g_ACompressionFormat = AudioChooseCompressor(hWnd, g_ACompressionFormat, NULL);
  896.         else {
  897.     
  898.             PCMWAVEFORMAT wfex;
  899.  
  900.             memcpy(&wfex, inputAudio->getWaveFormat(), sizeof(PCMWAVEFORMAT));
  901.             wfex.wf.wFormatTag = WAVE_FORMAT_PCM;
  902.  
  903.             switch(g_dubOpts.audio.newPrecision) {
  904.             case DubAudioOptions::P_8BIT:    wfex.wBitsPerSample = 8; break;
  905.             case DubAudioOptions::P_16BIT:    wfex.wBitsPerSample = 16; break;
  906.             }
  907.  
  908.             switch(g_dubOpts.audio.newPrecision) {
  909.             case DubAudioOptions::C_MONO:    wfex.wf.nChannels = 1; break;
  910.             case DubAudioOptions::C_STEREO:    wfex.wf.nChannels = 2; break;
  911.             }
  912.  
  913.             if (g_dubOpts.audio.new_rate) {
  914.                 long samp_frac;
  915.  
  916.                 if (g_dubOpts.audio.integral_rate)
  917.                     if (g_dubOpts.audio.new_rate > wfex.wf.nSamplesPerSec)
  918.                         samp_frac = 0x10000 / ((g_dubOpts.audio.new_rate + wfex.wf.nSamplesPerSec/2) / wfex.wf.nSamplesPerSec); 
  919.                     else
  920.                         samp_frac = 0x10000 * ((wfex.wf.nSamplesPerSec + g_dubOpts.audio.new_rate/2) / g_dubOpts.audio.new_rate);
  921.                 else
  922.                     samp_frac = MulDiv(wfex.wf.nSamplesPerSec, 0x10000L, g_dubOpts.audio.new_rate);
  923.  
  924.                 wfex.wf.nSamplesPerSec = MulDiv(wfex.wf.nSamplesPerSec, 0x10000L, samp_frac);
  925.             }
  926.  
  927.             wfex.wf.nBlockAlign = (wfex.wBitsPerSample+7)/8 * wfex.wf.nChannels;
  928.             wfex.wf.nAvgBytesPerSec = wfex.wf.nSamplesPerSec * wfex.wf.nBlockAlign;
  929.  
  930.             g_ACompressionFormat = AudioChooseCompressor(hWnd, g_ACompressionFormat, (WAVEFORMATEX *)&wfex);
  931.  
  932.         }
  933.  
  934.         if (g_ACompressionFormat) {
  935.             g_ACompressionFormatSize = sizeof(WAVEFORMATEX) + g_ACompressionFormat->cbSize;
  936.         }
  937. #endif
  938.         break;
  939.  
  940.     case ID_AUDIO_VOLUME:
  941.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_AUDIO_VOLUME), hWnd, AudioVolumeDlgProc);
  942.         break;
  943.  
  944.     case ID_AUDIO_SOURCE_NONE:
  945.         audioInputMode = AUDIOIN_NONE;
  946.         CloseWAV();
  947.         break;
  948.     case ID_AUDIO_SOURCE_AVI:
  949.         audioInputMode = AUDIOIN_AVI;
  950.         CloseWAV();
  951.         break;
  952.     case ID_AUDIO_SOURCE_WAV:
  953.         OpenWAV();
  954.         break;
  955.  
  956.     case ID_AUDIO_MODE_DIRECT:
  957.         g_dubOpts.audio.mode = DubAudioOptions::M_NONE;
  958.         break;
  959.     case ID_AUDIO_MODE_FULL:
  960.         g_dubOpts.audio.mode = DubAudioOptions::M_FULL;
  961.         break;
  962.  
  963.     case ID_OPTIONS_PERFORMANCE:
  964.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_PERFORMANCE), hWnd, PerformanceOptionsDlgProc);
  965.         break;
  966.     case ID_OPTIONS_DYNAMICCOMPILATION:
  967.         ActivateDubDialog(g_hInst, MAKEINTRESOURCE(IDD_PERF_DYNAMIC), hWnd, DynamicCompileOptionsDlgProc);
  968.         break;
  969.     case ID_OPTIONS_PREFERENCES:
  970.         DialogBox(g_hInst, MAKEINTRESOURCE(IDD_PREFERENCES), hWnd, PreferencesDlgProc);
  971.         break;
  972.     case ID_OPTIONS_DISPLAYINPUTVIDEO:
  973.         if (g_dubStatus)
  974.             g_dubStatus->ToggleFrame(false);
  975.         else
  976.             g_dubOpts.video.fShowInputFrame = !g_dubOpts.video.fShowInputFrame;
  977.         break;
  978.     case ID_OPTIONS_DISPLAYOUTPUTVIDEO:
  979.         if (g_dubStatus)
  980.             g_dubStatus->ToggleFrame(true);
  981.         else
  982.             g_dubOpts.video.fShowOutputFrame = !g_dubOpts.video.fShowOutputFrame;
  983.         break;
  984.     case ID_OPTIONS_DISPLAYDECOMPRESSEDOUTPUT:
  985.         g_drawDecompressedFrame = !g_drawDecompressedFrame;
  986.         break;
  987.     case ID_OPTIONS_SHOWSTATUSWINDOW:
  988.         if (g_dubStatus)
  989.             g_dubStatus->ToggleStatus();
  990.         else
  991.             g_showStatusWindow = !g_showStatusWindow;
  992.         break;
  993.     case ID_OPTIONS_SYNCHRONOUSBLIT:
  994.         g_syncroBlit = !g_syncroBlit;
  995.         break;
  996.     case ID_OPTIONS_VERTICALDISPLAY:
  997.         g_vertical = !g_vertical;
  998.         InvalidateRect(hWnd, NULL, TRUE);
  999.         break;
  1000.     case ID_OPTIONS_DRAWHISTOGRAMS:
  1001.         g_dubOpts.video.fHistogram = !g_dubOpts.video.fHistogram;
  1002.         break;
  1003.     case ID_OPTIONS_SYNCTOAUDIO:
  1004.         g_dubOpts.video.fSyncToAudio = !g_dubOpts.video.fSyncToAudio;
  1005.         break;
  1006.     case ID_OPTIONS_ENABLEDIRECTDRAW:
  1007.         g_dubOpts.perf.useDirectDraw = !g_dubOpts.perf.useDirectDraw;
  1008.         break;
  1009.     case ID_OPTIONS_DROPFRAMES:
  1010.         g_fDropFrames = !g_fDropFrames;
  1011.         break;
  1012.     case ID_OPTIONS_SWAPPANES:
  1013.         g_fSwapPanes = !g_fSwapPanes;
  1014.         InvalidateRect(hWnd, NULL, TRUE);
  1015.         break;
  1016.  
  1017.     case ID_OPTIONS_PREVIEWPROGRESSIVE:    g_dubOpts.video.nPreviewFieldMode = 0; break;
  1018.     case ID_OPTIONS_PREVIEWFIELDA:        g_dubOpts.video.nPreviewFieldMode = 1; break;
  1019.     case ID_OPTIONS_PREVIEWFIELDB:        g_dubOpts.video.nPreviewFieldMode = 2; break;
  1020.  
  1021.  
  1022.     case ID_TOOLS_HEXVIEWER:
  1023.         HexView(NULL);
  1024.         break;
  1025.  
  1026.  
  1027.     case ID_HELP_LICENSE:
  1028.         DisplayLicense(hWnd);
  1029.         break;
  1030.  
  1031.     case ID_HELP_CONTENTS:
  1032.         HelpShowHelp(hWnd);
  1033.         break;
  1034.     case ID_HELP_CHANGELOG:
  1035.         DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_SHOWTEXT), hWnd, ShowTextDlgProc, (LPARAM)MAKEINTRESOURCE(IDR_CHANGES));
  1036.         break;
  1037.     case ID_HELP_RELEASENOTES:
  1038.         DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_SHOWTEXT), hWnd, ShowTextDlgProc, (LPARAM)MAKEINTRESOURCE(IDR_RELEASE_NOTES));
  1039.         break;
  1040.     case ID_HELP_ABOUT:
  1041.         DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutDlgProc);
  1042.         break;
  1043.  
  1044.     case ID_HELP_ONLINE_HOME:    LaunchURL("http://www.virtualdub.org/index"); break;
  1045.     case ID_HELP_ONLINE_FAQ:    LaunchURL("http://www.virtualdub.org/virtualdub_faq"); break;
  1046.     case ID_HELP_ONLINE_NEWS:    LaunchURL("http://www.virtualdub.org/virtualdub_news"); break;
  1047.     case ID_HELP_ONLINE_KB:        LaunchURL("http://www.virtualdub.org/virtualdub_kb"); break;
  1048.  
  1049.     case ID_DUBINPROGRESS_ABORT:
  1050.         if (g_dubber) g_dubber->Abort();
  1051.         break;
  1052.  
  1053.  
  1054.     case ID_VIDEO_SEEK_START:
  1055.         PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_POSITION, PCN_START), (LPARAM)GetDlgItem(hWnd, IDC_POSITION));
  1056.         break;
  1057.     case ID_VIDEO_SEEK_END:
  1058.         PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_POSITION, PCN_END), (LPARAM)GetDlgItem(hWnd, IDC_POSITION));
  1059.         break;
  1060.     case ID_VIDEO_SEEK_PREV:
  1061.         PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_POSITION, PCN_BACKWARD), (LPARAM)GetDlgItem(hWnd, IDC_POSITION));
  1062.         break;
  1063.     case ID_VIDEO_SEEK_NEXT:
  1064.         PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_POSITION, PCN_FORWARD), (LPARAM)GetDlgItem(hWnd, IDC_POSITION));
  1065.         break;
  1066.     case ID_VIDEO_SEEK_PREVONESEC:
  1067.         {
  1068.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETPOS, 0, 0) - 50;
  1069.  
  1070.             if (lSample < 0)
  1071.                 lSample = 0;
  1072.  
  1073.             SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1074.             DisplayFrame(hWnd, lSample);
  1075.         }
  1076.         break;
  1077.     case ID_VIDEO_SEEK_NEXTONESEC:
  1078.         {
  1079.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETPOS, 0, 0) + 50;
  1080.             LONG lMax = (inputSubset ? inputSubset->getTotalFrames() : inputVideoAVI->lSampleLast);
  1081.  
  1082.             if (lSample > lMax)
  1083.                 lSample = lMax;
  1084.  
  1085.             SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1086.             DisplayFrame(hWnd, lSample);
  1087.         }
  1088.         break;
  1089.     case ID_VIDEO_SEEK_KEYPREV:
  1090.         PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_POSITION, PCN_KEYPREV), (LPARAM)GetDlgItem(hWnd, IDC_POSITION));
  1091.         break;
  1092.     case ID_VIDEO_SEEK_KEYNEXT:
  1093.         PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_POSITION, PCN_KEYNEXT), (LPARAM)GetDlgItem(hWnd, IDC_POSITION));
  1094.         break;
  1095.     case ID_VIDEO_SEEK_SELSTART:
  1096.         {
  1097.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETSELSTART, 0, 0);
  1098.  
  1099.             if (lSample >= 0) {
  1100.                 SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1101.                 DisplayFrame(hWnd, lSample);
  1102.             }
  1103.         }
  1104.         break;
  1105.     case ID_VIDEO_SEEK_SELEND:
  1106.         {
  1107.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETSELEND, 0, 0);
  1108.  
  1109.             if (lSample >= 0) {
  1110.                 SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1111.                 DisplayFrame(hWnd, lSample);
  1112.             }
  1113.         }
  1114.         break;
  1115.     case ID_VIDEO_SEEK_PREVDROP:
  1116.         if (inputAVI) {
  1117.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETPOS, 0, 0);
  1118.  
  1119.             while(--lSample >= (inputSubset ? 0 : inputVideoAVI->lSampleFirst)) {
  1120.                 int err;
  1121.                 long lBytes, lSamples;
  1122.  
  1123.                 err = inputVideoAVI->read(inputSubset ? inputSubset->lookupFrame(lSample) : lSample, 1, NULL, 0, &lBytes, &lSamples);
  1124.                 if (err != AVIERR_OK)
  1125.                     break;
  1126.  
  1127.                 if (!lBytes) {
  1128.                     SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1129.                     DisplayFrame(hWnd, lSample);
  1130.                     break;
  1131.                 }
  1132.             }
  1133.  
  1134.             if (lSample < (inputSubset ? 0 : inputVideoAVI->lSampleFirst))
  1135.                 guiSetStatus("No previous dropped frame found.", 255);
  1136.         }
  1137.         break;
  1138.  
  1139.     case ID_VIDEO_SEEK_NEXTDROP:
  1140.         if (inputAVI) {
  1141.             LONG lSample = SendDlgItemMessage(hWnd, IDC_POSITION, PCM_GETPOS, 0, 0);
  1142.  
  1143.             while(++lSample < (inputSubset ? inputSubset->getTotalFrames() : inputVideoAVI->lSampleLast)) {
  1144.                 int err;
  1145.                 long lBytes, lSamples;
  1146.  
  1147.                 err = inputVideoAVI->read(inputSubset ? inputSubset->lookupFrame(lSample) : lSample, 1, NULL, 0, &lBytes, &lSamples);
  1148.                 if (err != AVIERR_OK)
  1149.                     break;
  1150.  
  1151.                 if (!lBytes) {
  1152.                     SendDlgItemMessage(hWnd, IDC_POSITION, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1153.                     DisplayFrame(hWnd, lSample);
  1154.                     break;
  1155.                 }
  1156.             }
  1157.  
  1158.             if (lSample >= (inputSubset ? inputSubset->getTotalFrames() : inputVideoAVI->lSampleLast))
  1159.                 guiSetStatus("No next dropped frame found.", 255);
  1160.         }
  1161.         break;
  1162.  
  1163.     case ID_EDIT_JUMPTO:
  1164.         if (inputAVI) {
  1165.             long lFrame;
  1166.  
  1167.             lFrame = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_JUMPTOFRAME), g_hWnd, VideoJumpDlgProc, SendDlgItemMessage(g_hWnd, IDC_POSITION, PCM_GETPOS, 0, 0));
  1168.  
  1169.             if (lFrame >= 0) {
  1170.                 SendDlgItemMessage(g_hWnd, IDC_POSITION, PCM_SETPOS, TRUE, lFrame);
  1171.                 DisplayFrame(g_hWnd, SendDlgItemMessage(g_hWnd, IDC_POSITION, PCM_GETPOS, 0, 0));
  1172.             }
  1173.         }
  1174.         return TRUE;
  1175.  
  1176.     default:
  1177.         if (id >= ID_MRU_FILE0 && id <= ID_MRU_FILE3) {
  1178.             OpenAVI(id - ID_MRU_FILE0, (signed short)GetAsyncKeyState(VK_SHIFT) < 0);
  1179.             RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  1180.             break;
  1181.         }
  1182.         DragAcceptFiles(hWnd, TRUE);
  1183.         return FALSE;
  1184.     }
  1185.  
  1186.     SetTitleByFile(hWnd);
  1187.  
  1188.     DragAcceptFiles(hWnd, TRUE);
  1189.  
  1190.     // recompute some necessary things
  1191.  
  1192.     RecalcFrameSizes();
  1193.  
  1194.     return TRUE;
  1195. }
  1196.  
  1197. void RepaintMainWindow(HWND hWnd) {
  1198.     PAINTSTRUCT ps;
  1199.     HDC hDC;
  1200.     BITMAPINFOHEADER *formatIn;
  1201.  
  1202.     hDC = BeginPaint(hWnd, &ps);
  1203.     if (inputVideoAVI) {
  1204.         formatIn = inputVideoAVI->getImageFormat();
  1205.         if (formatIn) {
  1206.             BITMAPINFOHEADER *dcf = inputVideoAVI->getDecompressedFormat();
  1207.  
  1208. //            Draw3DRect(hDC, 2, 2, 8+formatIn->biWidth, 8+formatIn->biHeight, FALSE);
  1209. //            Draw3DRect(hDC, 5, 5, 2+formatIn->biWidth, 2+formatIn->biHeight, TRUE);
  1210.  
  1211.             Draw3DRect(hDC,
  1212.                     g_rInputFrame.left-4,
  1213.                     g_rInputFrame.top-4,
  1214.                     (g_rInputFrame.right-g_rInputFrame.left) + 8,
  1215.                     (g_rInputFrame.bottom-g_rInputFrame.top) + 8,
  1216.                     FALSE);
  1217.  
  1218.             Draw3DRect(hDC,
  1219.                     g_rInputFrame.left-1,
  1220.                     g_rInputFrame.top-1,
  1221.                     (g_rInputFrame.right-g_rInputFrame.left) + 2,
  1222.                     (g_rInputFrame.bottom-g_rInputFrame.top) + 2,
  1223.                     TRUE);
  1224.  
  1225.             // Skip the DrawDibDraw()s and filter processing if a dub is running.  Why?
  1226.             // The windows will likely get redrawn in 1/30s.  More importantly, we may be
  1227.             // using a format that GDI can't handle (like YUV), and we don't want
  1228.             // DrawDibDraw() loading all the codecs trying to find a codec to draw it.
  1229.  
  1230.             if (!g_dubber) {
  1231.                 if (inputVideoAVI->isFrameBufferValid())
  1232.                     DrawDibDraw(
  1233.                             hDDWindow,
  1234.                             hDC,
  1235.                             g_rInputFrame.left, g_rInputFrame.top,
  1236.                             (g_rInputFrame.right-g_rInputFrame.left), (g_rInputFrame.bottom-g_rInputFrame.top),
  1237.                             dcf,
  1238.                             inputVideoAVI->getFrameBuffer(),
  1239.                             0, 0, 
  1240.                             dcf->biWidth, dcf->biHeight,
  1241.                             0);
  1242.  
  1243.                 if (filters.isRunning()) {
  1244.                     VBitmap *out;
  1245.                     BITMAPINFOHEADER bihOutput;
  1246.  
  1247.                     out = filters.LastBitmap();
  1248.  
  1249.                     out->MakeBitmapHeader(&bihOutput);
  1250.  
  1251.                     DrawDibDraw(
  1252.                             hDDWindow2,
  1253.                             hDCWindow,
  1254.                             g_rOutputFrame.left, g_rOutputFrame.top,
  1255.                             g_rOutputFrame.right-g_rOutputFrame.left, g_rOutputFrame.bottom-g_rOutputFrame.top,
  1256.                             &bihOutput,
  1257.                             out->data,
  1258.                             0, 0, 
  1259.                             out->w, out->h,
  1260.                             0);
  1261.                 }
  1262.             }
  1263.  
  1264. //            Draw3DRect(hDC, 2, 12+formatIn->biHeight, 258, 258,TRUE);
  1265. //        if (outputAVI && outputAVI->videoOut && (formatOut = outputAVI->videoOut->getImageFormat())) {
  1266.             Draw3DRect(hDC,
  1267.                     g_rOutputFrame.left-4,
  1268.                     g_rOutputFrame.top-4,
  1269.                     (g_rOutputFrame.right-g_rOutputFrame.left) + 8,
  1270.                     (g_rOutputFrame.bottom-g_rOutputFrame.top) + 8,
  1271.                     FALSE);
  1272.  
  1273.             Draw3DRect(hDC,
  1274.                     g_rOutputFrame.left-1,
  1275.                     g_rOutputFrame.top-1,
  1276.                     (g_rOutputFrame.right-g_rOutputFrame.left) + 2,
  1277.                     (g_rOutputFrame.bottom-g_rOutputFrame.top) + 2,
  1278.                     TRUE);
  1279.         }
  1280.     }
  1281.     EndPaint(hWnd, &ps);
  1282. }
  1283.  
  1284. void MainMenuHelp(HWND hwnd, WPARAM wParam) {
  1285.     if (LOWORD(wParam) >= ID_MRU_FILE0 && LOWORD(wParam) <= ID_MRU_FILE3) {
  1286.         HWND hwndStatus = GetDlgItem(hwnd, IDC_STATUS_WINDOW);
  1287.         char name[1024];
  1288.  
  1289.         if ((HIWORD(wParam) & MF_POPUP) || (HIWORD(wParam) & MF_SYSMENU)) {
  1290.             SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)"");
  1291.             return;
  1292.         }
  1293.  
  1294.         strcpy(name, "[SHIFT for options] Load file ");
  1295.  
  1296.         if (!mru_list->get(LOWORD(wParam) - ID_MRU_FILE0, name+30, sizeof name - 30)) {
  1297.             SendMessage(hwndStatus, SB_SETTEXT, 255, (LPARAM)name);
  1298.         } else
  1299.             SendMessage(hwndStatus, SB_SETTEXT, 255, (LPARAM)"");
  1300.     } else
  1301.         guiMenuHelp(hwnd, wParam, 255, iMainMenuHelpTranslator);
  1302. }
  1303.  
  1304. bool DoFrameRightClick(HWND hwnd, LPARAM lParam) {
  1305.     POINT pt = { LOWORD(lParam), HIWORD(lParam) };
  1306.     bool isInput, isOutput;
  1307.  
  1308.     isInput        = !!PtInRect(&g_rInputFrame, pt);
  1309.     isOutput    = !!PtInRect(&g_rOutputFrame, pt);
  1310.  
  1311.     if (isInput || isOutput) {
  1312.         UINT res;
  1313.  
  1314.         ClientToScreen(hwnd, &pt);
  1315.  
  1316.         res = TrackPopupMenu(GetSubMenu(g_hmenuDisplay, 0), TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON|TPM_NONOTIFY|TPM_RETURNCMD,
  1317.             pt.x, pt.y, 0, hwnd, NULL);
  1318.  
  1319.         if (res >= ID_DISPLAY_QUARTER && res <= ID_DISPLAY_QUADRUPLE) {
  1320.             RECT r;
  1321.  
  1322.             if (isInput)
  1323.                 g_iInputFrameShift = res - ID_DISPLAY_NORMAL;
  1324.  
  1325.             if (isOutput)
  1326.                 g_iOutputFrameShift = res - ID_DISPLAY_NORMAL;
  1327.  
  1328.             RecalcFrameSizes();
  1329.  
  1330.             GetWindowRect(GetDlgItem(hwnd, IDC_POSITION), &r);
  1331.  
  1332.             ScreenToClient(hwnd, (LPPOINT)&r + 0);
  1333.             ScreenToClient(hwnd, (LPPOINT)&r + 1);
  1334.  
  1335.             r.bottom = r.top;
  1336.             r.right -= r.left;
  1337.             r.left = r.top = 0;
  1338.  
  1339.             InvalidateRect(hwnd, &r, TRUE);
  1340.             return true;
  1341.         }
  1342.     }
  1343.     return false;
  1344. }
  1345.  
  1346. LONG APIENTRY MainWndProc( HWND hWnd, UINT message, UINT wParam, LONG lParam)
  1347. {
  1348.     static HWND hwndItem0 = NULL;
  1349.     extern const unsigned char fht_tab[];
  1350.  
  1351.     switch (message) {
  1352.     case WM_CREATE:
  1353.         if (!(hDCWindow = GetDC(hWnd))) return -1;
  1354.         if (!(hDDWindow = DrawDibOpen())) return -1;
  1355.         if (!(hDDWindow2 = DrawDibOpen())) return -1;
  1356.  
  1357.         {
  1358.             HWND hwndItem;
  1359.             static const int widths[]={-1};
  1360.  
  1361.             if (!(hwndItem = CreateStatusWindow(WS_CHILD|WS_VISIBLE, "", hWnd, IDC_STATUS_WINDOW)))
  1362.                 return -1;
  1363.  
  1364.             SendMessage(hwndItem, SB_SIMPLE, TRUE, 0);
  1365.  
  1366.             if (!(hwndItem = CreateWindowEx(0, POSITIONCONTROLCLASS, "", WS_CHILD | WS_VISIBLE | PCS_PLAYBACK | PCS_MARK | PCS_SCENE, 0, 100, 200, 64, hWnd, (HMENU)IDC_POSITION, g_hInst, NULL)))
  1367.                 return -1;
  1368.  
  1369.             SendMessage(hwndItem, PCM_SETFRAMETYPECB, (WPARAM)&PositionFrameTypeCallback, 0);
  1370.         }
  1371.  
  1372.         MenuMRUListUpdate(hWnd);        
  1373.  
  1374. //        SetTimer(hWnd, 1, 5000, (TIMERPROC)NULL);
  1375.  
  1376.         return 0;
  1377.  
  1378.     case WM_INITMENU:
  1379.         {
  1380.             HMENU hMenu = (HMENU)wParam;
  1381.  
  1382.             CheckMenuRadioItem(hMenu, ID_AUDIO_SOURCE_NONE, ID_AUDIO_SOURCE_WAV, ID_AUDIO_SOURCE_NONE+audioInputMode, MF_BYCOMMAND);
  1383.             CheckMenuRadioItem(hMenu, ID_VIDEO_MODE_DIRECT, ID_VIDEO_MODE_FULL, ID_VIDEO_MODE_DIRECT+g_dubOpts.video.mode, MF_BYCOMMAND);
  1384.             CheckMenuRadioItem(hMenu, ID_AUDIO_MODE_DIRECT, ID_AUDIO_MODE_FULL, ID_AUDIO_MODE_DIRECT+g_dubOpts.audio.mode, MF_BYCOMMAND);
  1385.             CheckMenuRadioItem(hMenu, ID_OPTIONS_PREVIEWPROGRESSIVE, ID_OPTIONS_PREVIEWFIELDB,
  1386.                 ID_OPTIONS_PREVIEWPROGRESSIVE+g_dubOpts.video.nPreviewFieldMode, MF_BYCOMMAND);
  1387.  
  1388.             CheckMenuItem(hMenu, ID_OPTIONS_DISPLAYINPUTVIDEO    , MF_BYCOMMAND | (g_dubOpts.video.fShowInputFrame    ? MF_CHECKED : MF_UNCHECKED));
  1389.             CheckMenuItem(hMenu, ID_OPTIONS_DISPLAYOUTPUTVIDEO    , MF_BYCOMMAND | (g_dubOpts.video.fShowOutputFrame    ? MF_CHECKED : MF_UNCHECKED));
  1390.             CheckMenuItem(hMenu, ID_OPTIONS_DISPLAYDECOMPRESSEDOUTPUT, MF_BYCOMMAND | (g_drawDecompressedFrame ? MF_CHECKED : MF_UNCHECKED));
  1391.             CheckMenuItem(hMenu, ID_OPTIONS_SHOWSTATUSWINDOW    , MF_BYCOMMAND | (g_showStatusWindow    ? MF_CHECKED : MF_UNCHECKED));
  1392.             CheckMenuItem(hMenu, ID_OPTIONS_SYNCHRONOUSBLIT        , MF_BYCOMMAND | (g_syncroBlit            ? MF_CHECKED : MF_UNCHECKED));
  1393.             CheckMenuItem(hMenu, ID_OPTIONS_VERTICALDISPLAY        , MF_BYCOMMAND | (g_vertical            ? MF_CHECKED : MF_UNCHECKED));
  1394.             CheckMenuItem(hMenu, ID_OPTIONS_DRAWHISTOGRAMS        , MF_BYCOMMAND | (g_dubOpts.video.fHistogram        ? MF_CHECKED : MF_UNCHECKED));
  1395.             CheckMenuItem(hMenu, ID_OPTIONS_SYNCTOAUDIO            , MF_BYCOMMAND | (g_dubOpts.video.fSyncToAudio        ? MF_CHECKED : MF_UNCHECKED));
  1396.             CheckMenuItem(hMenu, ID_OPTIONS_ENABLEDIRECTDRAW    , MF_BYCOMMAND | (g_dubOpts.perf.useDirectDraw        ? MF_CHECKED : MF_UNCHECKED));
  1397.             CheckMenuItem(hMenu, ID_OPTIONS_DROPFRAMES            , MF_BYCOMMAND | (g_fDropFrames        ? MF_CHECKED : MF_UNCHECKED));
  1398.             CheckMenuItem(hMenu, ID_OPTIONS_SWAPPANES            , MF_BYCOMMAND | (g_fSwapPanes        ? MF_CHECKED : MF_UNCHECKED));
  1399.  
  1400.             DWORD dwEnableFlags = (inputAVI && inputAVI->Append(NULL) ? (MF_BYCOMMAND|MF_ENABLED) : (MF_BYCOMMAND|MF_GRAYED));
  1401.  
  1402.             EnableMenuItem(hMenu,ID_FILE_APPENDSEGMENT            , dwEnableFlags);
  1403.  
  1404.             dwEnableFlags = (inputAVI ? (MF_BYCOMMAND|MF_ENABLED) : (MF_BYCOMMAND|MF_GRAYED));
  1405.  
  1406.             EnableMenuItem(hMenu,ID_FILE_PREVIEWAVI                , dwEnableFlags);
  1407.             EnableMenuItem(hMenu,ID_FILE_SAVEAVI                , dwEnableFlags);
  1408.             EnableMenuItem(hMenu,ID_FILE_SAVECOMPATIBLEAVI        , dwEnableFlags);
  1409.             EnableMenuItem(hMenu,ID_FILE_SAVESTRIPEDAVI            , dwEnableFlags);
  1410.             EnableMenuItem(hMenu,ID_FILE_SAVESTRIPEMASTER        , dwEnableFlags);
  1411.             EnableMenuItem(hMenu,ID_FILE_SAVEIMAGESEQ            , dwEnableFlags);
  1412.             EnableMenuItem(hMenu,ID_FILE_SAVESEGMENTEDAVI        , dwEnableFlags);
  1413.             EnableMenuItem(hMenu,ID_FILE_SAVEWAV                , dwEnableFlags);
  1414.             EnableMenuItem(hMenu,ID_FILE_CLOSEAVI                , dwEnableFlags);
  1415.             EnableMenuItem(hMenu,ID_FILE_STARTSERVER            , dwEnableFlags);
  1416.             EnableMenuItem(hMenu,ID_FILE_AVIINFO                , dwEnableFlags);
  1417.  
  1418.             dwEnableFlags = ((g_dubOpts.audio.mode == DubAudioOptions::M_FULL) ? (MF_BYCOMMAND|MF_ENABLED) : (MF_BYCOMMAND|MF_GRAYED));
  1419.  
  1420.             EnableMenuItem(hMenu,ID_AUDIO_COMPRESSION            , dwEnableFlags);
  1421.             EnableMenuItem(hMenu,ID_AUDIO_CONVERSION            , dwEnableFlags);
  1422.             EnableMenuItem(hMenu,ID_AUDIO_VOLUME                , dwEnableFlags);
  1423.  
  1424.             dwEnableFlags = ((g_dubOpts.video.mode >= DubVideoOptions::M_FULL) ? (MF_BYCOMMAND|MF_ENABLED) : (MF_BYCOMMAND|MF_GRAYED));
  1425.             EnableMenuItem(hMenu,ID_VIDEO_FILTERS                , dwEnableFlags);
  1426.             dwEnableFlags = ((g_dubOpts.video.mode >= DubVideoOptions::M_SLOWREPACK) ? (MF_BYCOMMAND|MF_ENABLED) : (MF_BYCOMMAND|MF_GRAYED));
  1427.             EnableMenuItem(hMenu,ID_VIDEO_COLORDEPTH            , dwEnableFlags);
  1428.             dwEnableFlags = ((g_dubOpts.video.mode >= DubVideoOptions::M_FASTREPACK) ? (MF_BYCOMMAND|MF_ENABLED) : (MF_BYCOMMAND|MF_GRAYED));
  1429.             EnableMenuItem(hMenu,ID_VIDEO_COMPRESSION            , dwEnableFlags);
  1430.         }
  1431.         break;
  1432.  
  1433.     case WM_COMMAND:           // message: command from application menu
  1434.         if (lParam) {
  1435.             switch(LOWORD(wParam)) {
  1436.             case IDC_POSITION:
  1437.                 if (inputVideoAVI) switch(HIWORD(wParam)) {
  1438.                 case PCN_PLAY:
  1439.                 case PCN_PLAYPREVIEW:
  1440.                     SetAudioSource();
  1441.  
  1442.                     try {
  1443.                         LONG lStart = SendMessage((HWND)lParam, PCM_GETPOS, 0, 0);
  1444.                         DubOptions *dubOpt = new DubOptions(g_dubOpts);
  1445.                         LONG preload = inputAudio && inputAudio->getWaveFormat()->wFormatTag != WAVE_FORMAT_PCM ? 1000 : 500;
  1446.  
  1447.                         if (!dubOpt) throw MyMemoryError();
  1448.  
  1449.                         if (dubOpt->audio.preload > preload)
  1450.                             dubOpt->audio.preload = preload;
  1451.  
  1452.                         dubOpt->audio.interval                = 250;
  1453.                         dubOpt->audio.is_ms                    = TRUE;
  1454.                         dubOpt->video.lStartOffsetMS        = inputVideoAVI->samplesToMs(lStart);
  1455.  
  1456.                         if (HIWORD(wParam) != PCN_PLAYPREVIEW) {
  1457.                             dubOpt->audio.enabled                = TRUE;
  1458.                             dubOpt->audio.fStartAudio            = TRUE;
  1459.                             dubOpt->audio.new_rate                = 0;
  1460.                             dubOpt->audio.newPrecision            = DubAudioOptions::P_NOCHANGE;
  1461.                             dubOpt->audio.newChannels            = DubAudioOptions::C_NOCHANGE;
  1462.  
  1463.                             switch(g_prefs.main.iPreviewDepth) {
  1464.                             case PreferencesMain::DEPTH_DISPLAY:
  1465.                                 {
  1466.                                     DEVMODE dm;
  1467.                                     dm.dmSize = sizeof(DEVMODE);
  1468.                                     dm.dmDriverExtra = 0;
  1469.                                     if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
  1470.                                         dm.dmBitsPerPel = 16;
  1471.  
  1472.                                     switch(dm.dmBitsPerPel) {
  1473.                                     case 24:
  1474.                                     case 32:
  1475.                                         dubOpt->video.inputDepth = DubVideoOptions::D_24BIT;
  1476.                                         break;
  1477.                                     default:
  1478.                                         dubOpt->video.inputDepth = DubVideoOptions::D_16BIT;
  1479.                                         break;
  1480.                                     }
  1481.                                 }
  1482.                                 break;
  1483.                             case PreferencesMain::DEPTH_FASTEST:
  1484.                             case PreferencesMain::DEPTH_16BIT:
  1485.                                 dubOpt->video.inputDepth = DubVideoOptions::D_16BIT;
  1486.                                 break;
  1487.                             case PreferencesMain::DEPTH_24BIT:
  1488.                                 dubOpt->video.inputDepth = DubVideoOptions::D_24BIT;
  1489.                                 break;
  1490.  
  1491.                             // Ignore: PreferencesMain::DEPTH_OUTPUT
  1492.  
  1493.                             };
  1494.                             dubOpt->video.outputDepth            = dubOpt->video.inputDepth;
  1495.  
  1496.                             dubOpt->video.mode                    = DubVideoOptions::M_SLOWREPACK;
  1497.                             dubOpt->video.fShowInputFrame        = TRUE;
  1498.                             dubOpt->video.fShowOutputFrame        = FALSE;
  1499.                             dubOpt->video.frameRateDecimation    = 1;
  1500.                             dubOpt->video.frameRateNewMicroSecs    = 0;
  1501.                             dubOpt->video.lEndOffsetMS            = 0;
  1502.  
  1503.                             dubOpt->audio.mode                    = DubAudioOptions::M_FULL;
  1504.                         }
  1505.  
  1506.                         dubOpt->fShowStatus = false;
  1507.                         dubOpt->fMoveSlider = true;
  1508.  
  1509.                         if (lStart < inputVideoAVI->lSampleLast) {
  1510.         DragAcceptFiles(hWnd, FALSE);
  1511.         JobLockDubber();
  1512.                             PreviewAVI(hWnd, dubOpt, g_prefs.main.iPreviewPriority);
  1513.                             MenuMRUListUpdate(hWnd);
  1514.         JobUnlockDubber();
  1515.         DragAcceptFiles(hWnd, TRUE);
  1516.                         }
  1517.  
  1518.                         delete dubOpt;
  1519.                     } catch(MyError e) {
  1520.                         e.post(hWnd, g_szError);
  1521.                     }
  1522.                     break;
  1523.                 case PCN_MARKIN:
  1524.                     SendMessage(hWnd, WM_COMMAND, ID_EDIT_SETSELSTART, 0);
  1525.                     break;
  1526.                 case PCN_MARKOUT:
  1527.                     SendMessage(hWnd, WM_COMMAND, ID_EDIT_SETSELEND, 0);
  1528.                     break;
  1529.                 case PCN_START:
  1530.                     SendMessage((HWND)lParam, PCM_SETPOS, (WPARAM)TRUE, inputVideoAVI->lSampleFirst);
  1531.                     DisplayFrame(hWnd, inputVideoAVI->lSampleFirst);
  1532.                     break;
  1533.                 case PCN_BACKWARD:
  1534.                     {
  1535.                         LONG lSample = SendMessage((HWND)lParam, PCM_GETPOS, 0, 0);
  1536.  
  1537.                         if (lSample > inputVideoAVI->lSampleFirst) {
  1538.                             SendMessage((HWND)lParam, PCM_SETPOS, (WPARAM)TRUE, lSample-1);
  1539.                             DisplayFrame(hWnd, lSample-1);
  1540.                         }
  1541.                     }
  1542.                     break;
  1543.                 case PCN_FORWARD:
  1544.                     {
  1545.                         LONG lSample = SendMessage((HWND)lParam, PCM_GETPOS, 0, 0);
  1546.  
  1547.                         if (lSample < inputVideoAVI->lSampleLast) {
  1548.                             SendMessage((HWND)lParam, PCM_SETPOS, (WPARAM)TRUE, lSample+1);
  1549.                             DisplayFrame(hWnd, lSample+1);
  1550.                         }
  1551.                     }
  1552.                     break;
  1553.                 case PCN_END:
  1554.                     SendMessage((HWND)lParam, PCM_SETPOS, (WPARAM)TRUE, inputVideoAVI->lSampleLast);
  1555.                     DisplayFrame(hWnd, inputVideoAVI->lSampleLast);
  1556.                     break;
  1557.  
  1558.                 case PCN_KEYPREV:
  1559.                     {
  1560.                         LONG lSample = SendMessage((HWND)lParam, PCM_GETPOS, 0, 0);
  1561.  
  1562.                         if (inputSubset) {
  1563.                             long lSample2;
  1564.  
  1565.                             lSample2 = inputSubset->lookupFrame(lSample);
  1566.  
  1567.                             do {
  1568.                                 lSample2 = inputVideoAVI->prevKey(lSample2);
  1569.                                 lSample = inputSubset->revLookupFrame(lSample2);
  1570.                             } while(lSample2 >= 0 && lSample < 0);
  1571.                         } else
  1572.                             lSample = inputVideoAVI->prevKey(lSample);
  1573.  
  1574.                         if (lSample < 0) lSample = inputVideoAVI->lSampleFirst;
  1575.  
  1576.                         SendMessage((HWND)lParam, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1577.                         DisplayFrame(hWnd, lSample);
  1578.                     }
  1579.                     break;
  1580.                 case PCN_KEYNEXT:
  1581.                     {
  1582.                         LONG lSample = SendMessage((HWND)lParam, PCM_GETPOS, 0, 0);
  1583.  
  1584.                         if (inputSubset) {
  1585.                             long lSample2;
  1586.  
  1587.                             lSample2 = inputSubset->lookupFrame(lSample);
  1588.  
  1589.                             do {
  1590.                                 lSample2 = inputVideoAVI->nextKey(lSample2);
  1591.                                 lSample = inputSubset->revLookupFrame(lSample2);
  1592.                             } while(lSample2 >= 0 && lSample < 0);
  1593.                         } else
  1594.                             lSample = inputVideoAVI->nextKey(lSample);
  1595.  
  1596.                         if (lSample < 0) lSample = inputVideoAVI->lSampleLast;
  1597.  
  1598.                         SendMessage((HWND)lParam, PCM_SETPOS, (WPARAM)TRUE, lSample);
  1599.                         DisplayFrame(hWnd, lSample);
  1600.                     }
  1601.                     break;
  1602.  
  1603.                 case PCN_SCENEREV:
  1604.                     g_sceneShuttleMode = -1;
  1605.                     break;
  1606.  
  1607.                 case PCN_SCENEFWD:
  1608.                     g_sceneShuttleMode = +1;
  1609.                     break;
  1610.  
  1611.                 case PCN_STOP:
  1612.                 case PCN_SCENESTOP:
  1613. //                    g_sceneShuttleMode = 0;
  1614.                     SceneShuttleStop();
  1615.                     break;
  1616.  
  1617.                 }
  1618.                 break;
  1619.             }
  1620.         } else if (!MenuHit(hWnd, LOWORD(wParam)))
  1621.             return (DefWindowProc(hWnd, message, wParam, lParam));
  1622.         break;
  1623.  
  1624.     case WM_SIZE:
  1625.         guiRedoWindows(hWnd);
  1626.         break;
  1627.  
  1628.     case WM_DESTROY:                  // message: window being destroyed
  1629.         if (hDDWindow) DrawDibClose(hDDWindow);
  1630.         if (hDDWindow2) DrawDibClose(hDDWindow2);
  1631.         if (hDCWindow) ReleaseDC(hWnd, hDCWindow);
  1632.         PostQuitMessage(0);
  1633.         break;
  1634.  
  1635.     case WM_PAINT:
  1636.         RepaintMainWindow(hWnd);
  1637.         return TRUE;
  1638.  
  1639.     case WM_MENUSELECT:
  1640.         MainMenuHelp(hWnd, wParam);
  1641.         break;
  1642.  
  1643.     case WM_NOTIFY:
  1644.         {
  1645.             LPNMHDR nmh = (LPNMHDR)lParam;
  1646.             LONG pos;
  1647.  
  1648.             switch(nmh->idFrom) {
  1649.             case IDC_POSITION:
  1650.                 switch(nmh->code) {
  1651.                 case PCN_BEGINTRACK:
  1652.                     guiSetStatus("Seeking: hold SHIFT to snap to keyframes", 255);
  1653.                     SendMessage(nmh->hwndFrom, PCM_CTLAUTOFRAME, 0, 0);
  1654.                     break;
  1655.                 case PCN_ENDTRACK:
  1656.                     guiSetStatus("", 255);
  1657.                     SendMessage(nmh->hwndFrom, PCM_CTLAUTOFRAME, 0, 1);
  1658.                     break;
  1659.                 case PCN_THUMBPOSITION:
  1660.                 case PCN_THUMBTRACK:
  1661.                 case PCN_PAGELEFT:
  1662.                 case PCN_PAGERIGHT:
  1663.                     pos = SendMessage(nmh->hwndFrom, PCM_GETPOS, 0, 0);
  1664.  
  1665.                     if (inputVideoAVI) {
  1666.                         if (GetKeyState(VK_SHIFT)<0) {
  1667.                             if (inputSubset) {
  1668.                                 long lSample2;
  1669.  
  1670.                                 lSample2 = inputSubset->lookupFrame(pos);
  1671.  
  1672.                                 lSample2 = inputVideoAVI->nearestKey(lSample2);
  1673.                                 pos = inputSubset->revLookupFrame(lSample2);
  1674.                             } else
  1675.                                 pos = inputVideoAVI->nearestKey(pos);
  1676.  
  1677.                             if (nmh->code != PCN_THUMBTRACK)
  1678.                                 SendMessage(nmh->hwndFrom, PCM_SETPOS, TRUE, pos);
  1679.                         }
  1680.  
  1681.                         if (nmh->code == PCN_THUMBTRACK)
  1682.                             SendMessage(nmh->hwndFrom, PCM_SETDISPFRAME, 0, pos);
  1683.  
  1684.                         DisplayFrame(hWnd, pos);
  1685.                     }
  1686.                     break;
  1687.                 }
  1688.                 break;
  1689.             }
  1690.         }
  1691.         break;
  1692.  
  1693.     case WM_PALETTECHANGED:
  1694.         if ((HWND)wParam == hWnd)
  1695.             break;
  1696.     case WM_QUERYNEWPALETTE:
  1697.         DrawDibRealize(hDDWindow, hDCWindow, FALSE);
  1698.         break;
  1699.  
  1700.     case WM_KEYDOWN:
  1701.         switch((int)wParam) {
  1702.         case VK_F12:
  1703.             guiOpenDebug();
  1704.             break;
  1705.         }
  1706.         break;
  1707.  
  1708.     case WM_DROPFILES:
  1709.         HandleDragDrop((HDROP)wParam);
  1710.         break;
  1711.  
  1712.     case WM_RBUTTONDOWN:
  1713.         DoFrameRightClick(hWnd, lParam);
  1714.         UpdateWindow(hWnd);
  1715.         break;
  1716.  
  1717.     case WM_SETTEXT:
  1718.         if (!hwndItem0) {
  1719.             int i,j,k;
  1720.             const unsigned char *t = (const unsigned char *)lParam;
  1721.  
  1722.             for(i=strlen((const char *)t)-10; i>=0; i--) {
  1723.                 for(k=9; k>=0 && ((t[i+k]^fht_tab[k])==0xaa); k--)
  1724.                     ;
  1725.  
  1726.                 if (k<0)
  1727.                     break;
  1728.             }
  1729.             for(j=strlen((const char *)t)-9; j>=0; j--) {
  1730.                 for(k=8; k>=0 && ((t[j+k]^fht_tab[k+10])==0xaa); k--)
  1731.                     ;
  1732.  
  1733.                 if (k<0)
  1734.                     break;
  1735.             }
  1736.  
  1737.             hwndItem0 = GetDlgItem(hWnd, IDC_POSITION);
  1738.  
  1739.             SetWindowLong(hWnd, GWL_USERDATA, (i+1)*(j+1));
  1740.         }
  1741.     default:
  1742.         return (DefWindowProc(hWnd, message, wParam, lParam));
  1743.     }
  1744.     return (0);
  1745. }
  1746.  
  1747. //////////////////////////////////////////
  1748.  
  1749. LONG APIENTRY DubWndProc( HWND hWnd, UINT message, UINT wParam, LONG lParam)
  1750. {
  1751.     switch (message) {
  1752.     case WM_INITMENU:
  1753.         {
  1754.             HMENU hMenu = (HMENU)wParam;
  1755.             bool fShowStatusWindow = g_dubStatus->isVisible();
  1756.             bool fShowInputFrame = g_dubStatus->isFrameVisible(false);
  1757.             bool fShowOutputFrame = g_dubStatus->isFrameVisible(true);
  1758.  
  1759.             CheckMenuItem(hMenu, ID_OPTIONS_DISPLAYINPUTVIDEO    , MF_BYCOMMAND | (fShowInputFrame    ? MF_CHECKED : MF_UNCHECKED));
  1760.             CheckMenuItem(hMenu, ID_OPTIONS_DISPLAYOUTPUTVIDEO    , MF_BYCOMMAND | (fShowOutputFrame    ? MF_CHECKED : MF_UNCHECKED));
  1761.             CheckMenuItem(hMenu, ID_OPTIONS_SHOWSTATUSWINDOW    , MF_BYCOMMAND | (fShowStatusWindow    ? MF_CHECKED : MF_UNCHECKED));
  1762.         }
  1763.         break;
  1764.  
  1765.     case WM_COMMAND:
  1766.         if (lParam) {
  1767.             switch(LOWORD(wParam)) {
  1768.             case IDC_POSITION:
  1769.                 switch(HIWORD(wParam)) {
  1770.                 case PCN_STOP:
  1771.                     g_dubber->Abort();
  1772.                 }
  1773.                 break;
  1774.             }
  1775.         } else if (!MenuHit(hWnd, LOWORD(wParam)))
  1776.             return (DefWindowProc(hWnd, message, wParam, lParam));
  1777.         break;
  1778.  
  1779.     case WM_CLOSE:
  1780.         if (!g_showStatusWindow)
  1781.             MenuHit(hWnd, ID_OPTIONS_SHOWSTATUSWINDOW);
  1782.  
  1783.         if (IDYES == MessageBox(hWnd,
  1784.                 "A dub operation is currently in progress. Forcing VirtualDub to abort "
  1785.                 "will leave the output file unusable and may have undesirable side effects. "
  1786.                 "Do you really want to do this?"
  1787.                 ,"VirtualDub warning", MB_YESNO))
  1788.  
  1789.                 ExitProcess(1000);
  1790.         break;
  1791.  
  1792.     case WM_MOVE:
  1793.         {
  1794.             POINT pt;
  1795.  
  1796.             pt.x = pt.y = 0;
  1797.             ClientToScreen(hWnd, &pt);
  1798.             g_dubber->SetClientRectOffset(pt.x, pt.y);
  1799.         }
  1800.         break;
  1801.  
  1802.     case WM_SIZE:
  1803.         guiRedoWindows(hWnd);
  1804.         break;
  1805.  
  1806.     case WM_DESTROY:        // doh!!!!!!!
  1807.         PostQuitMessage(0);
  1808.         break;
  1809.  
  1810.     case WM_PAINT:
  1811.         RepaintMainWindow(hWnd);
  1812.         return TRUE;
  1813.  
  1814.     case WM_PALETTECHANGED:
  1815.         if ((HWND)wParam == hWnd)
  1816.             break;
  1817.     case WM_QUERYNEWPALETTE:
  1818.         g_dubber->RealizePalette();
  1819.         break;
  1820.  
  1821.     case WM_LBUTTONDOWN:
  1822.         if (wParam && MK_LBUTTON)
  1823.             g_dubber->Tag(LOWORD(lParam), HIWORD(lParam));
  1824.         break;
  1825.  
  1826.     case WM_RBUTTONDOWN:
  1827.         if (DoFrameRightClick(hWnd, lParam)) {
  1828.             g_dubber->SetFrameRectangles(&g_rInputFrame, &g_rOutputFrame);
  1829.         }
  1830.         break;
  1831.  
  1832.     default:
  1833.         return (DefWindowProc(hWnd, message, wParam, lParam));
  1834.     }
  1835.     return (0);
  1836. }
  1837.  
  1838.  
  1839.  
  1840.  
  1841.  
  1842.  
  1843.  
  1844. //////////////////////////////////////////////////////////////////////
  1845.  
  1846.  
  1847.  
  1848.  
  1849.  
  1850.  
  1851. extern const char fileFilters0[]=
  1852.         "Audio-Video Interleave (*.avi)\0"            "*.avi\0"
  1853.         "All files (*.*)\0"                            "*.*\0"
  1854.         ;
  1855.  
  1856. extern const char fileFiltersAppend[]=
  1857.         "VirtualDub/AVI_IO video segment (*.avi)\0"    "*.avi\0"
  1858.         "All files (*.*)\0"                            "*.*\0"
  1859.         ;
  1860.  
  1861. static const char fileFilters[]=
  1862.         "All usable types\0"                        "*.avi;*.avs;*.mpg;*.mpeg;*.mpv;*.m1v;*.dat;*.stripe;*.vdr\0"
  1863.         "Audio-Video Interleave (*.avi)\0"            "*.avi\0"
  1864.         "MPEG-1 video file (*.mpeg,*.mpg,*.mpv,*.dat)\0"    "*.mpg;*.mpeg;*.mpv;*.m1v;*.dat\0"
  1865.         "AVI stripe definition (*.stripe)\0"        "*.stripe\0"
  1866.         "VirtualDub remote signpost (*.vdr)\0"        "*.vdr\0"
  1867.         "AVI (compatibility mode) (*.avi,*.avs)\0"    "*.avi;*.avs\0"
  1868.         "All files (*.*)\0"                            "*.*\0"
  1869.         ;
  1870.  
  1871. static const char fileFilters2[]=
  1872.         "Windows audio (*.wav)\0"                    "*.wav\0"
  1873.         "All files (*.*)\0"                            "*.*\0"
  1874.         ;
  1875.  
  1876. static const char fileFiltersStripe[]=
  1877.         "AVI stripe definition (*.stripe)\0"        "*.stripe\0"
  1878.         "All files (*.*)\0"                            "*.*\0"
  1879.         ;
  1880.  
  1881. static const char fileFiltersSaveConfig[]=
  1882.         "VirtualDub configuration (*.vcf)\0"        "*.vcf\0"
  1883.         "Sylia script for VirtualDub (*.syl)\0"        "*.syl\0"
  1884.         "All files (*.*)\0"                            "*.*\0"
  1885.         ;
  1886.  
  1887.  
  1888. UINT CALLBACK OpenAVIDlgHookProc(  HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
  1889.     switch(uiMsg) {
  1890.     case WM_NOTIFY:
  1891.         if (((NMHDR *)lParam)->code == CDN_INITDONE) {
  1892.             CheckDlgButton(hDlg, IDC_AUTOLOADSEGMENTS, BST_CHECKED);
  1893.         } else if (((NMHDR *)lParam)->code == CDN_FILEOK) {
  1894.             OFNOTIFY *ofn = (OFNOTIFY *)lParam;
  1895.  
  1896.             ofn->lpOFN->lCustData    = (IsDlgButtonChecked(hDlg, IDC_EXTENDED_OPTIONS)?1:0)
  1897.                                     + (IsDlgButtonChecked(hDlg, IDC_AUTOLOADSEGMENTS)?2:0);
  1898.         }
  1899.         break;
  1900.     }
  1901.     return FALSE;
  1902. }
  1903.   
  1904. void OpenAVI(int index, bool ext_opt) {
  1905.     OPENFILENAME ofn;
  1906.     bool fExtendedOpen = false;
  1907.     bool fAutoscan = false;
  1908.  
  1909.     if (index<0) {
  1910.         ofn.lStructSize            = sizeof(OPENFILENAME);
  1911.         ofn.hwndOwner            = g_hWnd;
  1912.         ofn.lpstrFilter            = fileFilters;
  1913.         ofn.lpstrCustomFilter    = NULL;
  1914.         ofn.nFilterIndex        = 1;
  1915.         ofn.lpstrFile            = g_szInputAVIFile;
  1916.         ofn.nMaxFile            = sizeof g_szInputAVIFile;
  1917.         ofn.lpstrFileTitle        = g_szInputAVIFileTitle;
  1918.         ofn.nMaxFileTitle        = sizeof g_szInputAVIFileTitle;
  1919.         ofn.lpstrInitialDir        = NULL;
  1920.         ofn.lpstrTitle            = "Open video file";
  1921.         ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_ENABLESIZING;
  1922.         ofn.lpstrDefExt            = NULL;
  1923.         ofn.hInstance            = g_hInst;
  1924.         ofn.lpTemplateName        = MAKEINTRESOURCE(IDD_OPEN_AVI);
  1925.         ofn.lpfnHook            = (LPOFNHOOKPROC)OpenAVIDlgHookProc;
  1926.  
  1927.         if (!GetOpenFileName(&ofn)) return;
  1928.  
  1929.         fExtendedOpen = !!(ofn.lCustData&1);
  1930.         fAutoscan = !!(ofn.lCustData&2);
  1931.     } else {
  1932.         char name[MAX_PATH];
  1933.         char *name_ptr;
  1934.  
  1935.         ofn.nFilterIndex = 1;
  1936.  
  1937.         if (mru_list->get(index, name, sizeof name))
  1938.             return;
  1939.  
  1940.         mru_list->move_to_top(index);
  1941.  
  1942.         if (!GetFullPathName(name, sizeof g_szInputAVIFile, g_szInputAVIFile, &name_ptr))
  1943.             return;
  1944.  
  1945.         strcpy(g_szInputAVIFileTitle, name_ptr);
  1946.  
  1947.         fExtendedOpen = ext_opt;
  1948.         fAutoscan = true;
  1949.     }
  1950.  
  1951.     try {
  1952.         int iFileType;
  1953.         char *lpszName;
  1954.  
  1955.         switch(ofn.nFilterIndex) {
  1956.         case 2:
  1957.         case 5:    iFileType = FILETYPE_AVI; break;
  1958.         case 4: iFileType = FILETYPE_STRIPEDAVI; break;
  1959.         case 3: iFileType = FILETYPE_MPEG; break;
  1960. //        case 4: iFileType = FILETYPE_ASF; break;
  1961.         case 6: iFileType = FILETYPE_AVICOMPAT; break;
  1962.         default:iFileType = FILETYPE_AUTODETECT; break;
  1963.         }
  1964.  
  1965.         OpenAVI(g_szInputAVIFile, iFileType, fExtendedOpen, false, fAutoscan);
  1966.  
  1967.         lpszName = AutodetectFile(inputVideoAVI);
  1968.  
  1969.         if (lpszName)
  1970.             strcpy(g_szFileDescription, lpszName);
  1971.         else
  1972.             g_szFileDescription[0]=0;
  1973.  
  1974.         if (index<0)
  1975.             mru_list->add(g_szInputAVIFile);
  1976.     } catch(MyError e) {
  1977.         e.post(NULL, g_szError);
  1978.     }
  1979.     MenuMRUListUpdate(g_hWnd);
  1980. }
  1981.  
  1982. UINT CALLBACK AppendAVIDlgHookProc(  HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
  1983.     switch(uiMsg) {
  1984.     case WM_NOTIFY:
  1985.         if (((NMHDR *)lParam)->code == CDN_FILEOK) {
  1986.             OFNOTIFY *ofn = (OFNOTIFY *)lParam;
  1987.  
  1988.             ofn->lpOFN->lCustData    = (IsDlgButtonChecked(hDlg, IDC_AUTOAPPEND)?1:0);
  1989.         }
  1990.         break;
  1991.     }
  1992.     return FALSE;
  1993. }
  1994.  
  1995. void AppendAVI() {
  1996.     OPENFILENAME ofn;
  1997.     char szFileTitle[MAX_PATH];
  1998.  
  1999.     szFileTitle[0]=0;
  2000.  
  2001.     if (!inputAVI)
  2002.         return;
  2003.  
  2004.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2005.     ofn.hwndOwner            = g_hWnd;
  2006.     ofn.lpstrFilter            = fileFiltersAppend;
  2007.     ofn.lpstrCustomFilter    = NULL;
  2008.     ofn.nFilterIndex        = 1;
  2009.     ofn.lpstrFile            = g_szFile;
  2010.     ofn.nMaxFile            = sizeof g_szFile;
  2011.     ofn.lpstrFileTitle        = szFileTitle;
  2012.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2013.     ofn.lpstrInitialDir        = NULL;
  2014.     ofn.lpstrTitle            = "Append AVI segment";
  2015.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  2016.     ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "avi" : NULL;
  2017.     ofn.hInstance            = g_hInst;
  2018.     ofn.lpTemplateName        = MAKEINTRESOURCE(IDD_APPEND_AVI);
  2019.     ofn.lpfnHook            = (LPOFNHOOKPROC)AppendAVIDlgHookProc;
  2020.  
  2021.     if (!GetOpenFileName(&ofn)) return;
  2022.  
  2023.     try {
  2024.         if (ofn.lCustData)
  2025.             AppendAVIAutoscan(g_szFile);
  2026.         else
  2027.             AppendAVI(g_szFile);
  2028.     } catch(MyError e) {
  2029.         e.post(NULL, g_szError);
  2030.     }
  2031. }
  2032.  
  2033. void HandleDragDrop(HDROP hdrop) {
  2034.     char szName[MAX_PATH];
  2035.  
  2036.     if (DragQueryFile(hdrop, -1, NULL, 0) < 1)
  2037.         return;
  2038.  
  2039.     DragQueryFile(hdrop, 0, szName, sizeof szName);
  2040.  
  2041.     try {
  2042.         char *s;
  2043.  
  2044.         if (!GetFullPathName(szName, sizeof g_szInputAVIFile, g_szInputAVIFile, &s))
  2045.             return;
  2046.  
  2047.         strcpy(g_szInputAVIFileTitle, s);
  2048.  
  2049.         OpenAVI(g_szInputAVIFile, FILETYPE_AUTODETECT, false);
  2050.  
  2051.         mru_list->add(g_szInputAVIFile);
  2052.         MenuMRUListUpdate(g_hWnd);
  2053.         RecalcFrameSizes();
  2054.         SetTitleByFile(g_hWnd);
  2055.         RedrawWindow(g_hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  2056.     } catch(MyError e) {
  2057.         e.post(NULL, g_szError);
  2058.     }
  2059. }
  2060.  
  2061. ////////////////////////////////////
  2062.  
  2063. UINT CALLBACK SaveAVIDlgHookProc(  HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
  2064.     switch(uiMsg) {
  2065.     case WM_NOTIFY:
  2066.         if (((NMHDR *)lParam)->code == CDN_FILEOK) {
  2067.             OFNOTIFY *ofn = (OFNOTIFY *)lParam;
  2068.  
  2069.             ofn->lpOFN->lCustData = IsDlgButtonChecked(hDlg, IDC_ADD_AS_JOB);
  2070.         }
  2071.         break;
  2072.     }
  2073.     return FALSE;
  2074. }
  2075.   
  2076. void SaveAVI(HWND hWnd, bool fUseCompatibility) {
  2077.     OPENFILENAME ofn;
  2078.     char szFileTitle[MAX_PATH];
  2079.  
  2080.     ///////////////
  2081.  
  2082.     SetAudioSource();
  2083.  
  2084.     if (!inputVideoAVI) {
  2085.         MessageBox(hWnd, "No input video stream to process.", g_szError, MB_OK);
  2086.         return;
  2087.     }
  2088.  
  2089.     szFileTitle[0]=0;
  2090.  
  2091.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2092.     ofn.hwndOwner            = hWnd;
  2093.     ofn.lpstrFilter            = fileFilters0;
  2094.     ofn.lpstrCustomFilter    = NULL;
  2095.     ofn.nFilterIndex        = 1;
  2096.     ofn.lpstrFile            = g_szFile;
  2097.     ofn.nMaxFile            = sizeof g_szFile;
  2098.     ofn.lpstrFileTitle        = szFileTitle;
  2099.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2100.     ofn.lpstrInitialDir        = NULL;
  2101.     ofn.lpstrTitle            = fUseCompatibility ? "Save AVI 1.0 File" : "Save AVI 2.0 File";
  2102.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ENABLESIZING | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  2103.     ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "avi" : NULL;
  2104.     ofn.hInstance            = g_hInst;
  2105.     ofn.lpTemplateName        = MAKEINTRESOURCE(IDD_SAVE_OUTPUT);
  2106.     ofn.lpfnHook            = (LPOFNHOOKPROC)SaveAVIDlgHookProc;
  2107.  
  2108.     if (GetSaveFileName(&ofn)) {
  2109.         BOOL fAddAsJob = !!ofn.lCustData;
  2110.  
  2111.         if (!CoachCheckSaveOp(hWnd, &g_dubOpts, &g_Vcompression, g_ACompressionFormat, &g_listFA))
  2112.             return;
  2113.  
  2114.         if (fAddAsJob) {
  2115.             try {
  2116.                 JobAddConfiguration(&g_dubOpts, g_szInputAVIFile, FILETYPE_AUTODETECT, g_szFile, fUseCompatibility, &inputAVI->listFiles, 0, 0);
  2117.             } catch(MyError e) {
  2118.                 e.post(g_hWnd, g_szError);
  2119.             }
  2120.         } else {
  2121.             if (!(outputAVI = new AVIOutputFile()))
  2122.                 MessageBox(NULL,g_szOutOfMemory,g_szError,MB_OK);
  2123.             else {
  2124.                 ((AVIOutputFile *)outputAVI)->disable_os_caching();
  2125.  
  2126.                 if (g_prefs.fAVIRestrict1Gb)
  2127.                     ((AVIOutputFile *)outputAVI)->set_1Gb_limit();
  2128.  
  2129.                 if (fUseCompatibility)
  2130.                     ((AVIOutputFile *)outputAVI)->disable_extended_avi();
  2131.  
  2132.                 InitDubAVI(g_szFile, FALSE, NULL, g_prefs.main.iDubPriority, false, 0, 0);
  2133.             }
  2134.         }
  2135.     }
  2136. }
  2137.  
  2138. ///////////////////////////////////////////////////////////////////////////
  2139.  
  2140. struct SegmentValues {
  2141.     long lThreshMB;
  2142.     long lThreshFrames;
  2143.     bool fDefer;
  2144. };
  2145.  
  2146. UINT CALLBACK SaveSegmentedAVIDlgHookProc(  HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
  2147.     OFNOTIFY *ofn;
  2148.     BOOL fOk;
  2149.     SegmentValues *psv;
  2150.  
  2151.     switch(uiMsg) {
  2152.     case WM_COMMAND:
  2153.         switch(LOWORD(wParam)) {
  2154.         case IDC_FRAMELIMIT:
  2155.             if (HIWORD(wParam) == BN_CLICKED) {
  2156.                 EnableWindow(GetDlgItem(hDlg, IDC_EDIT_FRAMELIMIT), SendMessage((HWND)lParam, BM_GETSTATE, 0, 0));
  2157.             }
  2158.             break;
  2159.         }
  2160.         return 0;
  2161.  
  2162.     case WM_NOTIFY:
  2163.         ofn = (OFNOTIFY *)lParam;
  2164.  
  2165.         switch(ofn->hdr.code) {
  2166.         case CDN_INITDONE:
  2167.             SetDlgItemInt(hDlg, IDC_LIMIT, 2000, FALSE);
  2168.             break;
  2169.         case CDN_FILEOK:
  2170.             psv = (SegmentValues *)ofn->lpOFN->lCustData;
  2171.  
  2172.             psv->lThreshMB = GetDlgItemInt(hDlg, IDC_LIMIT, &fOk, FALSE);
  2173.  
  2174.             if (!fOk || psv->lThreshMB<50 || psv->lThreshMB>2048) {
  2175.                 MessageBox(hDlg, "The AVI segment size cannot be less than 50 or greater than 2048 megabytes.", g_szError, MB_OK);
  2176.                 SetFocus(GetDlgItem(hDlg, IDC_LIMIT));
  2177.  
  2178.                 SetWindowLong(hDlg, DWL_MSGRESULT, 1);
  2179.                 return 1;
  2180.             }
  2181.  
  2182.             if (IsDlgButtonChecked(hDlg, IDC_FRAMELIMIT)) {
  2183.                 psv->lThreshFrames = GetDlgItemInt(hDlg, IDC_EDIT_FRAMELIMIT, &fOk, FALSE);
  2184.  
  2185.                 if (!fOk || psv->lThreshFrames<1) {
  2186.                     MessageBox(hDlg, "AVI segments must have at least one frame.", g_szError, MB_OK);
  2187.                     SetFocus(GetDlgItem(hDlg, IDC_EDIT_FRAMELIMIT));
  2188.  
  2189.                     SetWindowLong(hDlg, DWL_MSGRESULT, 1);
  2190.                     return 1;
  2191.                 }
  2192.             } else
  2193.                 psv->lThreshFrames = 0;
  2194.  
  2195.             psv->fDefer = !!IsDlgButtonChecked(hDlg, IDC_ADD_AS_JOB);
  2196.  
  2197.             return 0;
  2198.         }
  2199.         break;
  2200.     }
  2201.     return FALSE;
  2202. }
  2203.   
  2204. void SaveSegmentedAVI(HWND hWnd) {
  2205.     OPENFILENAME ofn;
  2206.     char szFileTitle[MAX_PATH];
  2207.     SegmentValues sv;
  2208.  
  2209.     ///////////////
  2210.  
  2211.     SetAudioSource();
  2212.  
  2213.     if (!inputVideoAVI) {
  2214.         MessageBox(hWnd, "No input video stream to process.", g_szError, MB_OK);
  2215.         return;
  2216.     }
  2217.  
  2218.     szFileTitle[0]=0;
  2219.  
  2220.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2221.     ofn.hwndOwner            = hWnd;
  2222.     ofn.lpstrFilter            = fileFiltersAppend;
  2223.     ofn.lpstrCustomFilter    = NULL;
  2224.     ofn.nFilterIndex        = 1;
  2225.     ofn.lpstrFile            = g_szFile;
  2226.     ofn.nMaxFile            = sizeof g_szFile;
  2227.     ofn.lpstrFileTitle        = szFileTitle;
  2228.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2229.     ofn.lpstrInitialDir        = NULL;
  2230.     ofn.lpstrTitle            = "Save segmented AVI";
  2231.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  2232.     ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "avi" : NULL;
  2233.     ofn.hInstance            = g_hInst;
  2234.     ofn.lpTemplateName        = MAKEINTRESOURCE(IDD_SAVE_SEGMENTED);
  2235.     ofn.lpfnHook            = (LPOFNHOOKPROC)SaveSegmentedAVIDlgHookProc;
  2236.     ofn.lCustData            = (LONG)&sv;
  2237.  
  2238.     if (GetSaveFileName(&ofn)) {
  2239.         {
  2240.             char szPrefixBuffer[MAX_PATH], szPattern[MAX_PATH*2], *t, *t2, c;
  2241.             const char *s;
  2242.             int nMatchCount = 0;
  2243.  
  2244.             t = SplitPathName(g_szFile);
  2245.             t2 = SplitPathExt(t);
  2246.  
  2247.             if (!stricmp(t2, ".avi")) {
  2248.                 while(t2>t && isdigit((unsigned)t2[-1]))
  2249.                     --t2;
  2250.  
  2251.                 if (t2>t && t2[-1]=='.')
  2252.                     strcpy(t2, "avi");
  2253.             }
  2254.  
  2255.             strcpy(szPrefixBuffer, g_szFile);
  2256.             SplitPathExt(szPrefixBuffer)[0] = 0;
  2257.  
  2258.             s = SplitPathName(szPrefixBuffer);
  2259.             t = szPattern;
  2260.  
  2261.             while(*t++ = *s++)
  2262.                 if (s[-1]=='%')
  2263.                     *t++ = '%';
  2264.  
  2265.             t = szPrefixBuffer;
  2266.             while(*t)
  2267.                 ++t;
  2268.  
  2269.             strcpy(t, ".*.avi");
  2270.  
  2271.             WIN32_FIND_DATA wfd;
  2272.             HANDLE h;
  2273.  
  2274.             h = FindFirstFile(szPrefixBuffer, &wfd);
  2275.             if (h != INVALID_HANDLE_VALUE) {
  2276.                 strcat(szPattern, ".%d.av%c");
  2277.  
  2278.                 do {
  2279.                     int n;
  2280.  
  2281.                     if (2 == sscanf(wfd.cFileName, szPattern, &n, &c) && tolower(c)=='i')
  2282.                         ++nMatchCount;
  2283.                     
  2284.                 } while(FindNextFile(h, &wfd));
  2285.                 FindClose(h);
  2286.             }
  2287.  
  2288.             if (nMatchCount) {
  2289.                 if (IDOK != guiMessageBoxF(g_hWnd, g_szWarning, MB_OKCANCEL|MB_ICONEXCLAMATION,
  2290.                     "There %s %d existing file%s which match%s the filename pattern \"%s\". These files "
  2291.                     "will be erased if you continue, to prevent confusion with the new files."
  2292.                     ,nMatchCount==1 ? "is" : "are"
  2293.                     ,nMatchCount
  2294.                     ,nMatchCount==1 ? "" : "s"
  2295.                     ,nMatchCount==1 ? "es" : ""
  2296.                     ,SplitPathName(szPrefixBuffer)))
  2297.                     return;
  2298.  
  2299.                 h = FindFirstFile(szPrefixBuffer, &wfd);
  2300.                 if (h != INVALID_HANDLE_VALUE) {
  2301.                     strcat(szPattern, ".%d.av%c");
  2302.  
  2303.                     t = SplitPathName(szPrefixBuffer);
  2304.  
  2305.                     do {
  2306.                         int n;
  2307.  
  2308.                         if (2 == sscanf(wfd.cFileName, szPattern, &n, &c) && tolower(c)=='i') {
  2309.                             strcpy(t, wfd.cFileName);
  2310.                             DeleteFile(t);
  2311.                         }
  2312.                             
  2313.                         
  2314.                     } while(FindNextFile(h, &wfd));
  2315.                     FindClose(h);
  2316.                 }
  2317.             }
  2318.         }
  2319.  
  2320.         if (!CoachCheckSaveOp(hWnd, &g_dubOpts, &g_Vcompression, g_ACompressionFormat, &g_listFA))
  2321.             return;
  2322.  
  2323.         if (sv.fDefer) {
  2324.             try {
  2325.                 JobAddConfiguration(&g_dubOpts, g_szInputAVIFile, FILETYPE_AUTODETECT, g_szFile, true, &inputAVI->listFiles, sv.lThreshMB, sv.lThreshFrames);
  2326.             } catch(MyError e) {
  2327.                 e.post(g_hWnd, g_szError);
  2328.             }
  2329.         } else {
  2330.             if (!(outputAVI = new AVIOutputFile()))
  2331.                 MessageBox(NULL,g_szOutOfMemory,g_szError,MB_OK);
  2332.             else {
  2333.                 ((AVIOutputFile *)outputAVI)->disable_os_caching();
  2334.                 ((AVIOutputFile *)outputAVI)->disable_extended_avi();
  2335.                 ((AVIOutputFile *)outputAVI)->setSegmentHintBlock(true, NULL, 1);
  2336.  
  2337.                 InitDubAVI(g_szFile, FALSE, NULL, g_prefs.main.iDubPriority, false, sv.lThreshMB, sv.lThreshFrames);
  2338.             }
  2339.         }
  2340.     }
  2341. }
  2342.  
  2343. ///////////////////////////////////////////////////////////////////////////
  2344.  
  2345. void SaveStripedAVI(HWND hWnd) {
  2346.     OPENFILENAME ofn;
  2347.     char szFileTitle[MAX_PATH];
  2348.     AVIStripeSystem *stripe_def = NULL;
  2349.  
  2350.     ///////////////
  2351.  
  2352.     SetAudioSource();
  2353.  
  2354.     if (!inputVideoAVI) {
  2355.         MessageBox(hWnd, "No input video stream to process.", g_szError, MB_OK);
  2356.         return;
  2357.     }
  2358.  
  2359.     szFileTitle[0]=0;
  2360.  
  2361.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2362.     ofn.hwndOwner            = hWnd;
  2363.     ofn.lpstrFilter            = fileFiltersStripe;
  2364.     ofn.lpstrCustomFilter    = NULL;
  2365.     ofn.nFilterIndex        = 1;
  2366.     ofn.lpstrFile            = g_szFile;
  2367.     ofn.nMaxFile            = sizeof g_szFile;
  2368.     ofn.lpstrFileTitle        = szFileTitle;
  2369.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2370.     ofn.lpstrInitialDir        = NULL;
  2371.     ofn.lpstrTitle            = "Select AVI stripe definition file";
  2372.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING;
  2373.     ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "stripe" : NULL;
  2374.  
  2375.     try {
  2376.         if (GetOpenFileName(&ofn))
  2377.             SaveStripedAVI(g_szFile);
  2378.     } catch(MyError e) {
  2379.         e.post(NULL, g_szError);
  2380.     }
  2381.  
  2382.     delete stripe_def;
  2383. }
  2384.  
  2385. void SaveStripeMaster(HWND hWnd) {
  2386.     OPENFILENAME ofn;
  2387.     char szFileTitle[MAX_PATH];
  2388.     AVIStripeSystem *stripe_def = NULL;
  2389.  
  2390.     ///////////////
  2391.  
  2392.     SetAudioSource();
  2393.  
  2394.     if (!inputVideoAVI) {
  2395.         MessageBox(hWnd, "No input video stream to process.", g_szError, MB_OK);
  2396.         return;
  2397.     }
  2398.  
  2399.     szFileTitle[0]=0;
  2400.  
  2401.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2402.     ofn.hwndOwner            = hWnd;
  2403.     ofn.lpstrFilter            = fileFiltersStripe;
  2404.     ofn.lpstrCustomFilter    = NULL;
  2405.     ofn.nFilterIndex        = 1;
  2406.     ofn.lpstrFile            = g_szFile;
  2407.     ofn.nMaxFile            = sizeof g_szFile;
  2408.     ofn.lpstrFileTitle        = szFileTitle;
  2409.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2410.     ofn.lpstrInitialDir        = NULL;
  2411.     ofn.lpstrTitle            = "Select AVI stripe definition file";
  2412.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING;
  2413.     ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "stripe" : NULL;
  2414.  
  2415.     try {
  2416.         if (GetOpenFileName(&ofn))
  2417.             SaveStripeMaster(g_szFile);
  2418.     } catch(MyError e) {
  2419.         e.post(NULL, g_szError);
  2420.     }
  2421.  
  2422.     delete stripe_def;
  2423. }
  2424.  
  2425. void PreviewAVI(HWND hWnd, DubOptions *quick_options, int iPriority, bool fProp) {
  2426.     SetAudioSource();
  2427.  
  2428.     if (!inputVideoAVI) {
  2429.         MessageBox(hWnd, "No input video stream to process.", g_szError, MB_OK);
  2430.         return;
  2431.     }
  2432.  
  2433.     if (!(outputAVI = new AVIOutputPreview()))
  2434.         MessageBox(NULL, g_szOutOfMemory, g_szError,MB_OK);
  2435.     else
  2436.         InitDubAVI(NULL, FALSE, quick_options, iPriority, fProp, 0, 0);
  2437. }
  2438.  
  2439. void PositionCallback(LONG start, LONG cur, LONG end) {
  2440.     SendMessage(GetDlgItem(g_hWnd, IDC_POSITION), PCM_SETPOS, 0, cur);
  2441. }
  2442.  
  2443. void CPUTest() {
  2444.     long lEnableFlags;
  2445.  
  2446.     lEnableFlags = g_prefs.main.fOptimizations;
  2447.  
  2448.     if (!(g_prefs.main.fOptimizations & PreferencesMain::OPTF_FORCE)) {
  2449.         SYSTEM_INFO si;
  2450.  
  2451.         lEnableFlags = CPUCheckForExtensions();
  2452.  
  2453.         GetSystemInfo(&si);
  2454.  
  2455.         if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
  2456.             if (si.wProcessorLevel < 4)
  2457.                 lEnableFlags &= ~CPUF_SUPPORTS_FPU;        // Not strictly true, but very slow anyway
  2458.     }
  2459.  
  2460.     // Enable FPU support...
  2461.  
  2462.     long lActualEnabled = CPUEnableExtensions(lEnableFlags);
  2463. }
  2464.  
  2465. void InitDubAVI(char *szFile, BOOL fAudioOnly, DubOptions *quick_options, int iPriority, bool fPropagateErrors, long lSpillThreshold, long lSpillFrameThreshold) {
  2466.     char szSpillPrefix[MAX_PATH];
  2467.     bool fError = false;
  2468.     MyError prop_err;
  2469.     DubOptions *opts;
  2470.     POINT pt;
  2471.  
  2472.     try {
  2473.  
  2474.         filters.DeinitFilters();
  2475.         filters.DeallocateBuffers();
  2476.  
  2477.         SetAudioSource();
  2478.         RecalcFrameSizes();
  2479.  
  2480.         CPUTest();
  2481.  
  2482.         // Create a dubber.
  2483.  
  2484.         if (!quick_options) {
  2485.             g_dubOpts.video.fShowDecompressedFrame = g_drawDecompressedFrame;
  2486.             g_dubOpts.fShowStatus = !!g_showStatusWindow;
  2487.         }
  2488.  
  2489.         opts = quick_options ? quick_options : &g_dubOpts;
  2490.         opts->perf.fDropFrames = g_fDropFrames;
  2491.  
  2492.         if (!(g_dubber = CreateDubber(opts)))
  2493.             throw MyMemoryError();
  2494.  
  2495.         // Create dub status window
  2496.  
  2497.         g_dubStatus = CreateDubStatusHandler();
  2498.  
  2499.         if (opts->fMoveSlider)
  2500.             g_dubStatus->SetPositionCallback(g_fJobMode ? JobPositionCallback : PositionCallback);
  2501.  
  2502.         // Initialize the dubber.
  2503.  
  2504.         g_dubber->SetStatusHandler(g_dubStatus);
  2505.         g_dubber->SetInputFile(inputAVI);
  2506.         g_dubber->SetFrameRectangles(&g_rInputFrame, &g_rOutputFrame);
  2507.         pt.x = pt.y = 0;
  2508.         ClientToScreen(g_hWnd, &pt);
  2509.         g_dubber->SetClientRectOffset(pt.x, pt.y);
  2510.  
  2511.         if (!outputAVI->isPreview() && g_ACompressionFormat)
  2512.             g_dubber->SetAudioCompression(g_ACompressionFormat, g_ACompressionFormatSize);
  2513.  
  2514.         // As soon as we call Init(), this value is no longer ours to free.
  2515.  
  2516.         AVIOutput *pOutput = outputAVI;
  2517.  
  2518.         if (lSpillThreshold) {
  2519.             char szFile2[MAX_PATH];
  2520.  
  2521.             strcpy(szSpillPrefix, szFile);
  2522.             const_cast<char *>(SplitPathExt(szSpillPrefix))[0] = 0;
  2523.  
  2524.             strcpy(szFile2, szSpillPrefix);
  2525.             strcat(szFile2, ".00.avi");
  2526.  
  2527.             g_dubber->EnableSpill(szSpillPrefix, (__int64)(lSpillThreshold-1) << 20, lSpillFrameThreshold);
  2528.             outputAVI = NULL;
  2529.             g_dubber->Init(inputVideoAVI, inputAudio, pOutput, szFile2, hDCWindow, &g_Vcompression);
  2530.         } else if (fAudioOnly == 2) {
  2531.             g_dubber->SetPhantomVideoMode();
  2532.             outputAVI = NULL;
  2533.             g_dubber->Init(inputVideoAVI, inputAudio, pOutput, szFile, hDCWindow, &g_Vcompression);
  2534.         } else {
  2535.             outputAVI = NULL;
  2536.             g_dubber->Init(inputVideoAVI, inputAudio, pOutput, szFile, hDCWindow, &g_Vcompression);
  2537.         }
  2538.  
  2539.         _RPT0(0,"Starting dub.\n");
  2540.  
  2541.         if (!quick_options) RedrawWindow(g_hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  2542.  
  2543.         SetMenu(g_hWnd, hMenuDub);
  2544.         SetWindowLong(g_hWnd, GWL_WNDPROC, (DWORD)DubWndProc);
  2545.  
  2546.         g_dubber->Go(iPriority);
  2547.  
  2548.         if (g_dubber->isAbortedByUser())
  2549.             g_fJobAborted = true;
  2550.  
  2551.     } catch(char *s) {
  2552.         if (fPropagateErrors) {
  2553.             prop_err.setf(s);
  2554.             fError = true;
  2555.         } else
  2556.             MyError(s).post(g_hWnd,g_szError);
  2557.     } catch(MyError err) {
  2558.         if (fPropagateErrors) {
  2559.             prop_err = err;
  2560.             err.discard();
  2561.             fError = true;
  2562.         } else
  2563.             err.post(g_hWnd,g_szError);
  2564.     }
  2565.  
  2566.     g_dubber->SetStatusHandler(NULL);
  2567.     delete g_dubStatus; g_dubStatus = NULL;
  2568.  
  2569.     _CrtCheckMemory();
  2570.  
  2571.     SetMenu(g_hWnd, hMenuNormal);
  2572.     MenuMRUListUpdate(g_hWnd);
  2573.     SetWindowLong(g_hWnd, GWL_WNDPROC, (DWORD)MainWndProc);
  2574.  
  2575.     if (inputAVI)
  2576.         guiSetTitle(g_hWnd, IDS_TITLE_IDLE, g_szInputAVIFileTitle);
  2577.     else
  2578.         guiSetTitle(g_hWnd, IDS_TITLE_NOFILE);
  2579.  
  2580.     _RPT0(0,"Ending dub.\n");
  2581.  
  2582.     delete g_dubber;        g_dubber = NULL;
  2583.  
  2584.     CloseNewAVI();
  2585.  
  2586.     if (!inputVideoAVI->setDecompressedFormat(24))
  2587.         if (!inputVideoAVI->setDecompressedFormat(32))
  2588.             if (!inputVideoAVI->setDecompressedFormat(16))
  2589.                 inputVideoAVI->setDecompressedFormat(8);
  2590.  
  2591.     if (!quick_options) RedrawWindow(g_hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  2592.  
  2593.     if (fError && fPropagateErrors)
  2594.         throw prop_err;
  2595. }
  2596.  
  2597. /////////////////////////////
  2598.  
  2599. typedef struct SaveImageSeqDlgData {
  2600.     char szPrefix[MAX_PATH];
  2601.     char szPostfix[MAX_PATH];
  2602.     char szDirectory[MAX_PATH];
  2603.     char szFormat[MAX_PATH];
  2604.     int digits;
  2605.     long lFirstFrame, lLastFrame;
  2606. } SaveImageSeqDlgData;
  2607.  
  2608. static void SaveImageSeqShowFilenames(HWND hDlg) {
  2609.     SaveImageSeqDlgData *sisdd = (SaveImageSeqDlgData *)GetWindowLong(hDlg, DWL_USER);
  2610.     char buf[512], *s;
  2611.  
  2612.     if (!sisdd) return;
  2613.  
  2614.     strcpy(sisdd->szFormat, sisdd->szDirectory);
  2615.  
  2616.     s = sisdd->szFormat;
  2617.     while(*s) ++s;
  2618.     if (s>sisdd->szFormat && s[-1]!=':' && s[-1]!='\\')
  2619.         *s++ = '\\';
  2620.  
  2621.     strcpy(s, sisdd->szPrefix);
  2622.     while(*s) ++s;
  2623.  
  2624.     *s++ = '%';
  2625.     *s++ = '0';
  2626.     *s++ = '*';
  2627.     *s++ = 'l';
  2628.     *s++ = 'd';
  2629.  
  2630.     strcpy(s, sisdd->szPostfix);
  2631.  
  2632.     sprintf(buf, sisdd->szFormat, sisdd->digits, sisdd->lFirstFrame);
  2633.     SetDlgItemText(hDlg, IDC_STATIC_FIRSTFRAMENAME, buf);
  2634.     sprintf(buf, sisdd->szFormat, sisdd->digits, sisdd->lLastFrame);
  2635.     SetDlgItemText(hDlg, IDC_STATIC_LASTFRAMENAME, buf);
  2636. }
  2637.  
  2638. static BOOL CALLBACK SaveImageSeqDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  2639.     SaveImageSeqDlgData *sisdd = (SaveImageSeqDlgData *)GetWindowLong(hDlg, DWL_USER);
  2640.     char *lpszFileName;
  2641.     BROWSEINFO bi;
  2642.     LPITEMIDLIST pidlBrowse;
  2643.     LPMALLOC pMalloc;
  2644.     UINT uiTemp;
  2645.     BOOL fSuccess;
  2646.  
  2647.     switch(message) {
  2648.     case WM_INITDIALOG:
  2649.         SetWindowLong(hDlg, DWL_USER, NULL);
  2650.         sisdd = (SaveImageSeqDlgData *)lParam;
  2651.         SetDlgItemText(hDlg, IDC_FILENAME_PREFIX, sisdd->szPrefix);
  2652.         SetDlgItemText(hDlg, IDC_FILENAME_SUFFIX, sisdd->szPostfix);
  2653.         SetDlgItemInt(hDlg, IDC_FILENAME_DIGITS, sisdd->digits, FALSE);
  2654.         SetDlgItemText(hDlg, IDC_DIRECTORY, sisdd->szDirectory);
  2655.         SetWindowLong(hDlg, DWL_USER, lParam);
  2656.         SaveImageSeqShowFilenames(hDlg);
  2657.         return TRUE;
  2658.  
  2659.     case WM_COMMAND:
  2660.         if (!sisdd) break;
  2661.  
  2662.         switch(LOWORD(wParam)) {
  2663.  
  2664.         case IDC_FILENAME_PREFIX:
  2665.             if (HIWORD(wParam) != EN_CHANGE) break;
  2666.             SendMessage((HWND)lParam, WM_GETTEXT, sizeof sisdd->szPrefix, (LPARAM)sisdd->szPrefix);
  2667.             SaveImageSeqShowFilenames(hDlg);
  2668.             return TRUE;
  2669.  
  2670.         case IDC_FILENAME_SUFFIX:
  2671.             if (HIWORD(wParam) != EN_CHANGE) break;
  2672.             SendMessage((HWND)lParam, WM_GETTEXT, sizeof sisdd->szPostfix, (LPARAM)sisdd->szPostfix);
  2673.             SaveImageSeqShowFilenames(hDlg);
  2674.             return TRUE;
  2675.  
  2676.         case IDC_FILENAME_DIGITS:
  2677.             if (HIWORD(wParam) != EN_CHANGE) break;
  2678.             uiTemp = GetDlgItemInt(hDlg, IDC_FILENAME_DIGITS, &fSuccess, FALSE);
  2679.             if (fSuccess) {
  2680.                 sisdd->digits = uiTemp;
  2681.                 SaveImageSeqShowFilenames(hDlg);
  2682.             }
  2683.             return TRUE;
  2684.  
  2685.         case IDC_DIRECTORY:
  2686.             if (HIWORD(wParam) != EN_CHANGE) break;
  2687.             SendMessage((HWND)lParam, WM_GETTEXT, sizeof sisdd->szDirectory, (LPARAM)sisdd->szDirectory);
  2688.             SaveImageSeqShowFilenames(hDlg);
  2689.             return TRUE;
  2690.  
  2691.         case IDC_SELECT_DIR:
  2692.             if (SUCCEEDED(SHGetMalloc(&pMalloc))) {
  2693.                 if (lpszFileName = (char *)pMalloc->Alloc(MAX_PATH)) {
  2694.                     bi.hwndOwner        = hDlg;
  2695.                     bi.pidlRoot            = NULL;
  2696.                     bi.pszDisplayName    = lpszFileName;
  2697.                     bi.lpszTitle        = "Select a directory to save images to";
  2698.                     bi.ulFlags            = BIF_RETURNONLYFSDIRS;
  2699.                     bi.lpfn                = NULL;
  2700.  
  2701.                     if (pidlBrowse = SHBrowseForFolder(&bi)) {
  2702.                         if (SHGetPathFromIDList(pidlBrowse, lpszFileName))
  2703.                             SetDlgItemText(hDlg, IDC_DIRECTORY, lpszFileName);
  2704.  
  2705.                         pMalloc->Free(pidlBrowse);
  2706.                     }
  2707.                     pMalloc->Free(lpszFileName);
  2708.                 }
  2709.             }
  2710.             return TRUE;
  2711.  
  2712.         case IDOK:
  2713.             EndDialog(hDlg, TRUE);
  2714.             return TRUE;
  2715.  
  2716.         case IDCANCEL:
  2717.             EndDialog(hDlg, FALSE);
  2718.             return TRUE;
  2719.         }
  2720.         break;
  2721.     }
  2722.  
  2723.     return FALSE;
  2724. }
  2725.  
  2726. void SaveImageSeq(HWND hwnd) {
  2727.     SaveImageSeqDlgData sisdd;
  2728.  
  2729.     if (!inputVideoAVI) {
  2730.         MessageBox(hwnd, "No input video stream to process.", g_szError, MB_OK);
  2731.         return;
  2732.     }
  2733.  
  2734.     memset(&sisdd, 0, sizeof sisdd);
  2735.  
  2736.     strcpy(sisdd.szPostfix,".bmp");
  2737.     sisdd.lFirstFrame    = inputVideoAVI->lSampleFirst;
  2738.     sisdd.lLastFrame    = inputVideoAVI->lSampleLast-1;
  2739.  
  2740.     if (DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_AVIOUTPUTIMAGES_FORMAT), hwnd, SaveImageSeqDlgProc, (LPARAM)&sisdd)) {
  2741.         SetAudioSource();
  2742.  
  2743.         if (!(outputAVI = new AVIOutputImages(sisdd.szFormat, sisdd.digits)))
  2744.             MessageBox(NULL,g_szOutOfMemory,g_szError,MB_OK);
  2745.         else {
  2746.             InitDubAVI(NULL, FALSE, NULL, g_prefs.main.iDubPriority);
  2747.         }
  2748.     }
  2749. }
  2750.  
  2751. /////////////////////////////
  2752.  
  2753.  
  2754. void SaveWAV(HWND hWnd) {
  2755.     OPENFILENAME ofn;
  2756.     char szFileTitle[MAX_PATH];
  2757.  
  2758.     //////////
  2759.  
  2760.     SetAudioSource();
  2761.  
  2762.     if (!inputAudio) {
  2763.         MessageBox(g_hWnd, "No input audio stream to extract.", g_szError, MB_OK);
  2764.         return;
  2765.     }
  2766.  
  2767.     szFileTitle[0]=0;
  2768.  
  2769.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2770.     ofn.hwndOwner            = g_hWnd;
  2771.     ofn.lpstrFilter            = fileFilters2;
  2772.     ofn.lpstrCustomFilter    = NULL;
  2773.     ofn.nFilterIndex        = 1;
  2774.     ofn.lpstrFile            = g_szFile;
  2775.     ofn.nMaxFile            = sizeof g_szFile;
  2776.     ofn.lpstrFileTitle        = szFileTitle;
  2777.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2778.     ofn.lpstrInitialDir        = NULL;
  2779.     ofn.lpstrTitle            = "Save WAV File";
  2780.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_OVERWRITEPROMPT;
  2781.     ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "wav" : NULL;
  2782.  
  2783.     if (GetSaveFileName(&ofn))
  2784.         try {
  2785.             SaveWAV(g_szFile);
  2786.         } catch(MyError e) {
  2787.             e.post(NULL, g_szError);
  2788.         }
  2789. }
  2790.  
  2791. ///////////////
  2792.  
  2793. void OpenWAV() {
  2794.     OPENFILENAME ofn;
  2795.     char szFileTitle[MAX_PATH];
  2796.  
  2797.     szFileTitle[0]=0;
  2798.  
  2799.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2800.     ofn.hwndOwner            = g_hWnd;
  2801.     ofn.lpstrFilter            = fileFilters2;
  2802.     ofn.lpstrCustomFilter    = NULL;
  2803.     ofn.nFilterIndex        = 1;
  2804.     ofn.lpstrFile            = g_szInputWAVFile;
  2805.     ofn.nMaxFile            = sizeof g_szInputWAVFile;
  2806.     ofn.lpstrFileTitle        = szFileTitle;
  2807.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2808.     ofn.lpstrInitialDir        = NULL;
  2809.     ofn.lpstrTitle            = "Open WAV File";
  2810.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING;
  2811.     ofn.lpstrDefExt            = NULL;
  2812.  
  2813.     if (GetOpenFileName(&ofn))
  2814.         OpenWAV(g_szInputWAVFile);
  2815. }
  2816.  
  2817. /////////////////////////////////////////////////////////////////////////////////
  2818.  
  2819. void SaveConfiguration(HWND hWnd) {
  2820.     OPENFILENAME ofn;
  2821.     char szFileTitle[MAX_PATH];
  2822.  
  2823.     //////////
  2824.  
  2825.     szFileTitle[0]=0;
  2826.  
  2827.     ofn.lStructSize            = sizeof(OPENFILENAME);
  2828.     ofn.hwndOwner            = g_hWnd;
  2829.     ofn.lpstrFilter            = fileFiltersSaveConfig;
  2830.     ofn.lpstrCustomFilter    = NULL;
  2831.     ofn.nFilterIndex        = 1;
  2832.     ofn.lpstrFile            = g_szFile;
  2833.     ofn.nMaxFile            = sizeof g_szFile;
  2834.     ofn.lpstrFileTitle        = szFileTitle;
  2835.     ofn.nMaxFileTitle        = sizeof szFileTitle;
  2836.     ofn.lpstrInitialDir        = NULL;
  2837.     ofn.lpstrTitle            = "Save Configuration";
  2838.     ofn.Flags                = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_OVERWRITEPROMPT;
  2839.     ofn.lpstrDefExt            = g_prefs.main.fAttachExtension ? "vcf" : NULL;
  2840.  
  2841.     if (GetSaveFileName(&ofn)) {
  2842.         FILE *f = NULL;
  2843.         try {
  2844.             f = fopen(g_szFile, "w");
  2845.  
  2846.             if (!f)
  2847.                 throw MyError("Cannot open output file: %s.", strerror(errno));
  2848.  
  2849.             JobWriteConfiguration(f, &g_dubOpts);
  2850.  
  2851.             fclose(f);
  2852.             f = NULL;
  2853.         } catch(MyError e) {
  2854.             e.post(NULL, g_szError);
  2855.         }
  2856.  
  2857.         if (f)
  2858.             fclose(f);
  2859.     }
  2860. }
  2861.  
  2862. /////////////////////////////////////////////////////////////////////////////////
  2863.  
  2864. void DoDelete() {
  2865.     if (!inputVideoAVI)
  2866.         return;
  2867.  
  2868.     try {
  2869.         HWND hwndPosition = GetDlgItem(g_hWnd, IDC_POSITION);
  2870.         LONG lSample = SendMessage(hwndPosition, PCM_GETPOS, 0, 0);
  2871.         LONG lStart = SendMessage(hwndPosition, PCM_GETSELSTART, 0, 0);
  2872.         LONG lEnd = SendMessage(hwndPosition, PCM_GETSELEND, 0, 0);
  2873.  
  2874.         if (!inputSubset)
  2875.             if (!(inputSubset = new FrameSubset(inputVideoAVI->lSampleLast - inputVideoAVI->lSampleFirst)))
  2876.                 throw MyMemoryError();
  2877.  
  2878. //        _RPT0(0,"Deleting 1 frame\n");
  2879.  
  2880.         if (lStart>=0 && lEnd>=0 && lEnd>=lStart)
  2881.             inputSubset->deleteRange(lStart, lEnd+1-lStart);
  2882.         else
  2883.             inputSubset->deleteRange(lSample, 1);
  2884.  
  2885.         SendMessage(hwndPosition, PCM_SETRANGEMAX, (BOOL)TRUE, inputSubset->getTotalFrames());
  2886.         SendMessage(hwndPosition, PCM_CLEARSEL, (BOOL)TRUE, 0);
  2887.         SendMessage(hwndPosition, PCM_SETPOS, (BOOL)TRUE, lStart);
  2888.         g_dubOpts.video.lStartOffsetMS = g_dubOpts.video.lEndOffsetMS = 0;
  2889.  
  2890.         DisplayFrame(g_hWnd, SendMessage(hwndPosition, PCM_GETPOS, 0, 0));
  2891.     } catch(MyError e) {
  2892.         e.post(g_hWnd, g_szError);
  2893.     }
  2894. }
  2895.  
  2896. ///////////////////////////////////////////
  2897.  
  2898.